crl.c (96998B)
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 /* 6 * Moved from secpkcs7.c 7 */ 8 9 #include "cert.h" 10 #include "certi.h" 11 #include "secder.h" 12 #include "secasn1.h" 13 #include "secoid.h" 14 #include "certdb.h" 15 #include "certxutl.h" 16 #include "prtime.h" 17 #include "secerr.h" 18 #include "pk11func.h" 19 #include "dev.h" 20 #include "dev3hack.h" 21 #include "nssbase.h" 22 #if defined(DPC_RWLOCK) || defined(GLOBAL_RWLOCK) 23 #include "nssrwlk.h" 24 #endif 25 #include "pk11priv.h" 26 27 const SEC_ASN1Template SEC_CERTExtensionTemplate[] = { 28 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertExtension) }, 29 { SEC_ASN1_OBJECT_ID, offsetof(CERTCertExtension, id) }, 30 { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */ 31 offsetof(CERTCertExtension, critical) }, 32 { SEC_ASN1_OCTET_STRING, offsetof(CERTCertExtension, value) }, 33 { 0 } 34 }; 35 36 static const SEC_ASN1Template SEC_CERTExtensionsTemplate[] = { 37 { SEC_ASN1_SEQUENCE_OF, 0, SEC_CERTExtensionTemplate } 38 }; 39 40 /* 41 * XXX Also, these templates need to be tested; Lisa did the obvious 42 * translation but they still should be verified. 43 */ 44 45 const SEC_ASN1Template CERT_IssuerAndSNTemplate[] = { 46 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTIssuerAndSN) }, 47 { SEC_ASN1_SAVE, offsetof(CERTIssuerAndSN, derIssuer) }, 48 { SEC_ASN1_INLINE, offsetof(CERTIssuerAndSN, issuer), CERT_NameTemplate }, 49 { SEC_ASN1_INTEGER, offsetof(CERTIssuerAndSN, serialNumber) }, 50 { 0 } 51 }; 52 53 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) 54 SEC_ASN1_MKSUB(CERT_TimeChoiceTemplate) 55 56 static const SEC_ASN1Template cert_CrlKeyTemplate[] = { 57 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCrlKey) }, 58 { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(CERTCrlKey, dummy) }, 59 { SEC_ASN1_SKIP }, 60 { SEC_ASN1_ANY, offsetof(CERTCrlKey, derName) }, 61 { SEC_ASN1_SKIP_REST }, 62 { 0 } 63 }; 64 65 static const SEC_ASN1Template cert_CrlEntryTemplate[] = { 66 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCrlEntry) }, 67 { SEC_ASN1_INTEGER, offsetof(CERTCrlEntry, serialNumber) }, 68 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTCrlEntry, revocationDate), 69 SEC_ASN1_SUB(CERT_TimeChoiceTemplate) }, 70 { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF, 71 offsetof(CERTCrlEntry, extensions), SEC_CERTExtensionTemplate }, 72 { 0 } 73 }; 74 75 const SEC_ASN1Template CERT_CrlTemplate[] = { 76 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCrl) }, 77 { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(CERTCrl, version) }, 78 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTCrl, signatureAlg), 79 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 80 { SEC_ASN1_SAVE, offsetof(CERTCrl, derName) }, 81 { SEC_ASN1_INLINE, offsetof(CERTCrl, name), CERT_NameTemplate }, 82 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTCrl, lastUpdate), 83 SEC_ASN1_SUB(CERT_TimeChoiceTemplate) }, 84 { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN, 85 offsetof(CERTCrl, nextUpdate), SEC_ASN1_SUB(CERT_TimeChoiceTemplate) }, 86 { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF, offsetof(CERTCrl, entries), 87 cert_CrlEntryTemplate }, 88 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 89 SEC_ASN1_EXPLICIT | 0, 90 offsetof(CERTCrl, extensions), SEC_CERTExtensionsTemplate }, 91 { 0 } 92 }; 93 94 const SEC_ASN1Template CERT_CrlTemplateNoEntries[] = { 95 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCrl) }, 96 { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(CERTCrl, version) }, 97 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTCrl, signatureAlg), 98 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 99 { SEC_ASN1_SAVE, offsetof(CERTCrl, derName) }, 100 { SEC_ASN1_INLINE, offsetof(CERTCrl, name), CERT_NameTemplate }, 101 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTCrl, lastUpdate), 102 SEC_ASN1_SUB(CERT_TimeChoiceTemplate) }, 103 { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN, 104 offsetof(CERTCrl, nextUpdate), SEC_ASN1_SUB(CERT_TimeChoiceTemplate) }, 105 { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF | 106 SEC_ASN1_SKIP }, /* skip entries */ 107 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 108 SEC_ASN1_EXPLICIT | 0, 109 offsetof(CERTCrl, extensions), SEC_CERTExtensionsTemplate }, 110 { 0 } 111 }; 112 113 const SEC_ASN1Template CERT_CrlTemplateEntriesOnly[] = { 114 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCrl) }, 115 { SEC_ASN1_SKIP | SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL }, 116 { SEC_ASN1_SKIP }, 117 { SEC_ASN1_SKIP }, 118 { SEC_ASN1_SKIP | SEC_ASN1_INLINE | SEC_ASN1_XTRN, 119 offsetof(CERTCrl, lastUpdate), SEC_ASN1_SUB(CERT_TimeChoiceTemplate) }, 120 { SEC_ASN1_SKIP | SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN, 121 offsetof(CERTCrl, nextUpdate), SEC_ASN1_SUB(CERT_TimeChoiceTemplate) }, 122 { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF, offsetof(CERTCrl, entries), 123 cert_CrlEntryTemplate }, /* decode entries */ 124 { SEC_ASN1_SKIP_REST }, 125 { 0 } 126 }; 127 128 const SEC_ASN1Template CERT_SignedCrlTemplate[] = { 129 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTSignedCrl) }, 130 { SEC_ASN1_SAVE, offsetof(CERTSignedCrl, signatureWrap.data) }, 131 { SEC_ASN1_INLINE, offsetof(CERTSignedCrl, crl), CERT_CrlTemplate }, 132 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 133 offsetof(CERTSignedCrl, signatureWrap.signatureAlgorithm), 134 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 135 { SEC_ASN1_BIT_STRING, offsetof(CERTSignedCrl, signatureWrap.signature) }, 136 { 0 } 137 }; 138 139 static const SEC_ASN1Template cert_SignedCrlTemplateNoEntries[] = { 140 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTSignedCrl) }, 141 { SEC_ASN1_SAVE, offsetof(CERTSignedCrl, signatureWrap.data) }, 142 { SEC_ASN1_INLINE, offsetof(CERTSignedCrl, crl), 143 CERT_CrlTemplateNoEntries }, 144 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 145 offsetof(CERTSignedCrl, signatureWrap.signatureAlgorithm), 146 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 147 { SEC_ASN1_BIT_STRING, offsetof(CERTSignedCrl, signatureWrap.signature) }, 148 { 0 } 149 }; 150 151 const SEC_ASN1Template CERT_SetOfSignedCrlTemplate[] = { 152 { SEC_ASN1_SET_OF, 0, CERT_SignedCrlTemplate }, 153 }; 154 155 /* get CRL version */ 156 int 157 cert_get_crl_version(CERTCrl* crl) 158 { 159 /* CRL version is defaulted to v1 */ 160 int version = SEC_CRL_VERSION_1; 161 if (crl && crl->version.data != 0) { 162 version = (int)DER_GetUInteger(&crl->version); 163 } 164 return version; 165 } 166 167 /* check the entries in the CRL */ 168 SECStatus 169 cert_check_crl_entries(CERTCrl* crl) 170 { 171 CERTCrlEntry** entries; 172 CERTCrlEntry* entry; 173 PRBool hasCriticalExten = PR_FALSE; 174 SECStatus rv = SECSuccess; 175 176 if (!crl) { 177 return SECFailure; 178 } 179 180 if (crl->entries == NULL) { 181 /* CRLs with no entries are valid */ 182 return (SECSuccess); 183 } 184 185 /* Look in the crl entry extensions. If there is a critical extension, 186 then the crl version must be v2; otherwise, it should be v1. 187 */ 188 entries = crl->entries; 189 while (*entries) { 190 entry = *entries; 191 if (entry->extensions) { 192 /* If there is a critical extension in the entries, then the 193 CRL must be of version 2. If we already saw a critical 194 extension, 195 there is no need to check the version again. 196 */ 197 if (hasCriticalExten == PR_FALSE) { 198 hasCriticalExten = cert_HasCriticalExtension(entry->extensions); 199 if (hasCriticalExten) { 200 if (cert_get_crl_version(crl) != SEC_CRL_VERSION_2) { 201 /* only CRL v2 critical extensions are supported */ 202 PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION); 203 rv = SECFailure; 204 break; 205 } 206 } 207 } 208 209 /* For each entry, make sure that it does not contain an unknown 210 critical extension. If it does, we must reject the CRL since 211 we don't know how to process the extension. 212 */ 213 if (cert_HasUnknownCriticalExten(entry->extensions) == PR_TRUE) { 214 PORT_SetError(SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION); 215 rv = SECFailure; 216 break; 217 } 218 } 219 ++entries; 220 } 221 return (rv); 222 } 223 224 /* Check the version of the CRL. If there is a critical extension in the crl 225 or crl entry, then the version must be v2. Otherwise, it should be v1. If 226 the crl contains critical extension(s), then we must recognized the 227 extension's OID. 228 */ 229 SECStatus 230 cert_check_crl_version(CERTCrl* crl) 231 { 232 PRBool hasCriticalExten = PR_FALSE; 233 int version = cert_get_crl_version(crl); 234 235 if (version > SEC_CRL_VERSION_2) { 236 PORT_SetError(SEC_ERROR_CRL_INVALID_VERSION); 237 return (SECFailure); 238 } 239 240 /* Check the crl extensions for a critial extension. If one is found, 241 and the version is not v2, then we are done. 242 */ 243 if (crl->extensions) { 244 hasCriticalExten = cert_HasCriticalExtension(crl->extensions); 245 if (hasCriticalExten) { 246 if (version != SEC_CRL_VERSION_2) { 247 /* only CRL v2 critical extensions are supported */ 248 PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION); 249 return (SECFailure); 250 } 251 /* make sure that there is no unknown critical extension */ 252 if (cert_HasUnknownCriticalExten(crl->extensions) == PR_TRUE) { 253 PORT_SetError(SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION); 254 return (SECFailure); 255 } 256 } 257 } 258 259 return (SECSuccess); 260 } 261 262 /* 263 * Generate a database key, based on the issuer name from a 264 * DER crl. 265 */ 266 SECStatus 267 CERT_KeyFromDERCrl(PLArenaPool* arena, SECItem* derCrl, SECItem* key) 268 { 269 SECStatus rv; 270 CERTSignedData sd; 271 CERTCrlKey crlkey; 272 PLArenaPool* myArena; 273 274 if (!arena) { 275 /* arena needed for QuickDER */ 276 myArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 277 } else { 278 myArena = arena; 279 } 280 PORT_Memset(&sd, 0, sizeof(sd)); 281 rv = SEC_QuickDERDecodeItem(myArena, &sd, CERT_SignedDataTemplate, derCrl); 282 if (SECSuccess == rv) { 283 PORT_Memset(&crlkey, 0, sizeof(crlkey)); 284 rv = SEC_QuickDERDecodeItem(myArena, &crlkey, cert_CrlKeyTemplate, 285 &sd.data); 286 } 287 288 /* make a copy so the data doesn't point to memory inside derCrl, which 289 may be temporary */ 290 if (SECSuccess == rv) { 291 rv = SECITEM_CopyItem(arena, key, &crlkey.derName); 292 } 293 294 if (myArena != arena) { 295 PORT_FreeArena(myArena, PR_FALSE); 296 } 297 298 return rv; 299 } 300 301 #define GetOpaqueCRLFields(x) ((OpaqueCRLFields*)x->opaque) 302 303 SECStatus 304 CERT_CompleteCRLDecodeEntries(CERTSignedCrl* crl) 305 { 306 SECStatus rv = SECSuccess; 307 SECItem* crldata = NULL; 308 OpaqueCRLFields* extended = NULL; 309 310 if ((!crl) || (!(extended = (OpaqueCRLFields*)crl->opaque)) || 311 (PR_TRUE == extended->decodingError)) { 312 rv = SECFailure; 313 } else { 314 if (PR_FALSE == extended->partial) { 315 /* the CRL has already been fully decoded */ 316 return SECSuccess; 317 } 318 if (PR_TRUE == extended->badEntries) { 319 /* the entries decoding already failed */ 320 return SECFailure; 321 } 322 crldata = &crl->signatureWrap.data; 323 if (!crldata) { 324 rv = SECFailure; 325 } 326 } 327 328 if (SECSuccess == rv) { 329 rv = SEC_QuickDERDecodeItem(crl->arena, &crl->crl, 330 CERT_CrlTemplateEntriesOnly, crldata); 331 if (SECSuccess == rv) { 332 extended->partial = PR_FALSE; /* successful decode, avoid 333 decoding again */ 334 } else { 335 extended->decodingError = PR_TRUE; 336 extended->badEntries = PR_TRUE; 337 /* cache the decoding failure. If it fails the first time, 338 it will fail again, which will grow the arena and leak 339 memory, so we want to avoid it */ 340 } 341 rv = cert_check_crl_entries(&crl->crl); 342 if (rv != SECSuccess) { 343 extended->badExtensions = PR_TRUE; 344 } 345 } 346 return rv; 347 } 348 349 /* 350 * take a DER CRL and decode it into a CRL structure 351 * allow reusing the input DER without making a copy 352 */ 353 CERTSignedCrl* 354 CERT_DecodeDERCrlWithFlags(PLArenaPool* narena, SECItem* derSignedCrl, int type, 355 PRInt32 options) 356 { 357 PLArenaPool* arena; 358 CERTSignedCrl* crl; 359 SECStatus rv; 360 OpaqueCRLFields* extended = NULL; 361 const SEC_ASN1Template* crlTemplate = CERT_SignedCrlTemplate; 362 PRInt32 testOptions = options; 363 364 PORT_Assert(derSignedCrl); 365 if (!derSignedCrl) { 366 PORT_SetError(SEC_ERROR_INVALID_ARGS); 367 return NULL; 368 } 369 370 /* Adopting DER requires not copying it. Code that sets ADOPT flag 371 * but doesn't set DONT_COPY probably doesn't know What it is doing. 372 * That condition is a programming error in the caller. 373 */ 374 testOptions &= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER); 375 PORT_Assert(testOptions != CRL_DECODE_ADOPT_HEAP_DER); 376 if (testOptions == CRL_DECODE_ADOPT_HEAP_DER) { 377 PORT_SetError(SEC_ERROR_INVALID_ARGS); 378 return NULL; 379 } 380 381 /* make a new arena if needed */ 382 if (narena == NULL) { 383 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 384 if (!arena) { 385 return NULL; 386 } 387 } else { 388 arena = narena; 389 } 390 391 /* allocate the CRL structure */ 392 crl = (CERTSignedCrl*)PORT_ArenaZAlloc(arena, sizeof(CERTSignedCrl)); 393 if (!crl) { 394 PORT_SetError(SEC_ERROR_NO_MEMORY); 395 goto loser; 396 } 397 398 crl->arena = arena; 399 400 /* allocate opaque fields */ 401 crl->opaque = (void*)PORT_ArenaZAlloc(arena, sizeof(OpaqueCRLFields)); 402 if (!crl->opaque) { 403 goto loser; 404 } 405 extended = (OpaqueCRLFields*)crl->opaque; 406 if (options & CRL_DECODE_ADOPT_HEAP_DER) { 407 extended->heapDER = PR_TRUE; 408 } 409 if (options & CRL_DECODE_DONT_COPY_DER) { 410 crl->derCrl = derSignedCrl; /* DER is not copied . The application 411 must keep derSignedCrl until it 412 destroys the CRL */ 413 } else { 414 crl->derCrl = (SECItem*)PORT_ArenaZAlloc(arena, sizeof(SECItem)); 415 if (crl->derCrl == NULL) { 416 goto loser; 417 } 418 rv = SECITEM_CopyItem(arena, crl->derCrl, derSignedCrl); 419 if (rv != SECSuccess) { 420 goto loser; 421 } 422 } 423 424 /* Save the arena in the inner crl for CRL extensions support */ 425 crl->crl.arena = arena; 426 if (options & CRL_DECODE_SKIP_ENTRIES) { 427 crlTemplate = cert_SignedCrlTemplateNoEntries; 428 extended->partial = PR_TRUE; 429 } 430 431 /* decode the CRL info */ 432 switch (type) { 433 case SEC_CRL_TYPE: 434 rv = SEC_QuickDERDecodeItem(arena, crl, crlTemplate, crl->derCrl); 435 if (rv != SECSuccess) { 436 extended->badDER = PR_TRUE; 437 break; 438 } 439 /* check for critical extensions */ 440 rv = cert_check_crl_version(&crl->crl); 441 if (rv != SECSuccess) { 442 extended->badExtensions = PR_TRUE; 443 break; 444 } 445 446 if (PR_TRUE == extended->partial) { 447 /* partial decoding, don't verify entries */ 448 break; 449 } 450 451 rv = cert_check_crl_entries(&crl->crl); 452 if (rv != SECSuccess) { 453 extended->badExtensions = PR_TRUE; 454 } 455 456 break; 457 458 default: 459 PORT_SetError(SEC_ERROR_INVALID_ARGS); 460 rv = SECFailure; 461 break; 462 } 463 464 if (rv != SECSuccess) { 465 goto loser; 466 } 467 468 crl->referenceCount = 1; 469 470 return (crl); 471 472 loser: 473 if (options & CRL_DECODE_KEEP_BAD_CRL) { 474 if (extended) { 475 extended->decodingError = PR_TRUE; 476 } 477 if (crl) { 478 crl->referenceCount = 1; 479 return (crl); 480 } 481 } 482 483 if ((narena == NULL) && arena) { 484 PORT_FreeArena(arena, PR_FALSE); 485 } 486 487 return (0); 488 } 489 490 /* 491 * take a DER CRL and decode it into a CRL structure 492 */ 493 CERTSignedCrl* 494 CERT_DecodeDERCrl(PLArenaPool* narena, SECItem* derSignedCrl, int type) 495 { 496 return CERT_DecodeDERCrlWithFlags(narena, derSignedCrl, type, 497 CRL_DECODE_DEFAULT_OPTIONS); 498 } 499 500 /* 501 * Lookup a CRL in the databases. We mirror the same fast caching data base 502 * caching stuff used by certificates....? 503 * return values : 504 * 505 * SECSuccess means we got a valid decodable DER CRL, or no CRL at all. 506 * Caller may distinguish those cases by the value returned in "decoded". 507 * When DER CRL is not found, error code will be SEC_ERROR_CRL_NOT_FOUND. 508 * 509 * SECFailure means we got a fatal error - most likely, we found a CRL, 510 * and it failed decoding, or there was an out of memory error. Do NOT ignore 511 * it and specifically do NOT treat it the same as having no CRL, as this 512 * can compromise security !!! Ideally, you should treat this case as if you 513 * received a "catch-all" CRL where all certs you were looking up are 514 * considered to be revoked 515 */ 516 static SECStatus 517 SEC_FindCrlByKeyOnSlot(PK11SlotInfo* slot, SECItem* crlKey, int type, 518 CERTSignedCrl** decoded, PRInt32 decodeoptions) 519 { 520 SECStatus rv = SECSuccess; 521 CERTSignedCrl* crl = NULL; 522 SECItem* derCrl = NULL; 523 CK_OBJECT_HANDLE crlHandle = 0; 524 char* url = NULL; 525 526 PORT_Assert(decoded); 527 if (!decoded) { 528 PORT_SetError(SEC_ERROR_INVALID_ARGS); 529 return SECFailure; 530 } 531 532 derCrl = PK11_FindCrlByName(&slot, &crlHandle, crlKey, type, &url); 533 if (derCrl == NULL) { 534 /* if we had a problem other than the CRL just didn't exist, return 535 * a failure to the upper level */ 536 int nsserror = PORT_GetError(); 537 if (nsserror != SEC_ERROR_CRL_NOT_FOUND) { 538 rv = SECFailure; 539 } 540 goto loser; 541 } 542 PORT_Assert(crlHandle != CK_INVALID_HANDLE); 543 /* PK11_FindCrlByName obtained a slot reference. */ 544 545 /* derCRL is a fresh HEAP copy made for us by PK11_FindCrlByName. 546 Force adoption of the DER CRL from the heap - this will cause it 547 to be automatically freed when SEC_DestroyCrl is invoked */ 548 decodeoptions |= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER); 549 550 crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl, type, decodeoptions); 551 if (crl) { 552 crl->slot = slot; 553 slot = NULL; /* adopt it */ 554 derCrl = NULL; /* adopted by the crl struct */ 555 crl->pkcs11ID = crlHandle; 556 if (url) { 557 crl->url = PORT_ArenaStrdup(crl->arena, url); 558 } 559 } else { 560 rv = SECFailure; 561 } 562 563 if (url) { 564 PORT_Free(url); 565 } 566 567 if (slot) { 568 PK11_FreeSlot(slot); 569 } 570 571 loser: 572 if (derCrl) { 573 SECITEM_FreeItem(derCrl, PR_TRUE); 574 } 575 576 *decoded = crl; 577 578 return rv; 579 } 580 581 CERTSignedCrl* 582 crl_storeCRL(PK11SlotInfo* slot, char* url, CERTSignedCrl* newCrl, 583 SECItem* derCrl, int type) 584 { 585 CERTSignedCrl *oldCrl = NULL, *crl = NULL; 586 PRBool deleteOldCrl = PR_FALSE; 587 CK_OBJECT_HANDLE crlHandle = CK_INVALID_HANDLE; 588 589 PORT_Assert(newCrl); 590 PORT_Assert(derCrl); 591 PORT_Assert(type == SEC_CRL_TYPE); 592 593 if (type != SEC_CRL_TYPE) { 594 PORT_SetError(SEC_ERROR_INVALID_ARGS); 595 return NULL; 596 } 597 598 /* we can't use the cache here because we must look in the same 599 token */ 600 (void)SEC_FindCrlByKeyOnSlot(slot, &newCrl->crl.derName, type, &oldCrl, 601 CRL_DECODE_SKIP_ENTRIES); 602 /* if there is an old crl on the token, make sure the one we are 603 installing is newer. If not, exit out, otherwise delete the 604 old crl. 605 */ 606 if (oldCrl != NULL) { 607 /* if it's already there, quietly continue */ 608 if (SECITEM_CompareItem(newCrl->derCrl, oldCrl->derCrl) == SECEqual) { 609 crl = newCrl; 610 crl->slot = PK11_ReferenceSlot(slot); 611 crl->pkcs11ID = oldCrl->pkcs11ID; 612 if (oldCrl->url && !url) 613 url = oldCrl->url; 614 if (url) 615 crl->url = PORT_ArenaStrdup(crl->arena, url); 616 goto done; 617 } 618 if (!SEC_CrlIsNewer(&newCrl->crl, &oldCrl->crl)) { 619 PORT_SetError(SEC_ERROR_OLD_CRL); 620 goto done; 621 } 622 623 /* if we have a url in the database, use that one */ 624 if (oldCrl->url && !url) { 625 url = oldCrl->url; 626 } 627 628 /* really destroy this crl */ 629 /* first drum it out of the permanment Data base */ 630 deleteOldCrl = PR_TRUE; 631 } 632 633 /* invalidate CRL cache for this issuer */ 634 CERT_CRLCacheRefreshIssuer(NULL, &newCrl->crl.derName); 635 /* Write the new entry into the data base */ 636 crlHandle = PK11_PutCrl(slot, derCrl, &newCrl->crl.derName, url, type); 637 if (crlHandle != CK_INVALID_HANDLE) { 638 crl = newCrl; 639 crl->slot = PK11_ReferenceSlot(slot); 640 crl->pkcs11ID = crlHandle; 641 if (url) { 642 crl->url = PORT_ArenaStrdup(crl->arena, url); 643 } 644 } 645 646 done: 647 if (oldCrl) { 648 if (deleteOldCrl && crlHandle != CK_INVALID_HANDLE) { 649 SEC_DeletePermCRL(oldCrl); 650 } 651 SEC_DestroyCrl(oldCrl); 652 } 653 654 return crl; 655 } 656 657 /* 658 * 659 * create a new CRL from DER material. 660 * 661 * The signature on this CRL must be checked before you 662 * load it. ??? 663 */ 664 CERTSignedCrl* 665 SEC_NewCrl(CERTCertDBHandle* handle, char* url, SECItem* derCrl, int type) 666 { 667 CERTSignedCrl* retCrl = NULL; 668 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); 669 retCrl = 670 PK11_ImportCRL(slot, derCrl, url, type, NULL, CRL_IMPORT_BYPASS_CHECKS, 671 NULL, CRL_DECODE_DEFAULT_OPTIONS); 672 PK11_FreeSlot(slot); 673 674 return retCrl; 675 } 676 677 CERTSignedCrl* 678 SEC_FindCrlByDERCert(CERTCertDBHandle* handle, SECItem* derCrl, int type) 679 { 680 PLArenaPool* arena; 681 SECItem crlKey; 682 SECStatus rv; 683 CERTSignedCrl* crl = NULL; 684 685 /* create a scratch arena */ 686 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 687 if (arena == NULL) { 688 return (NULL); 689 } 690 691 /* extract the database key from the cert */ 692 rv = CERT_KeyFromDERCrl(arena, derCrl, &crlKey); 693 if (rv != SECSuccess) { 694 goto loser; 695 } 696 697 /* find the crl */ 698 crl = SEC_FindCrlByName(handle, &crlKey, type); 699 700 loser: 701 PORT_FreeArena(arena, PR_FALSE); 702 return (crl); 703 } 704 705 CERTSignedCrl* 706 SEC_DupCrl(CERTSignedCrl* acrl) 707 { 708 if (acrl) { 709 PR_ATOMIC_INCREMENT(&acrl->referenceCount); 710 return acrl; 711 } 712 return NULL; 713 } 714 715 SECStatus 716 SEC_DestroyCrl(CERTSignedCrl* crl) 717 { 718 if (crl) { 719 if (PR_ATOMIC_DECREMENT(&crl->referenceCount) < 1) { 720 if (crl->slot) { 721 PK11_FreeSlot(crl->slot); 722 } 723 if (GetOpaqueCRLFields(crl) && 724 PR_TRUE == GetOpaqueCRLFields(crl)->heapDER) { 725 SECITEM_FreeItem(crl->derCrl, PR_TRUE); 726 } 727 if (crl->arena) { 728 PORT_FreeArena(crl->arena, PR_FALSE); 729 } 730 } 731 return SECSuccess; 732 } else { 733 return SECFailure; 734 } 735 } 736 737 SECStatus 738 SEC_LookupCrls(CERTCertDBHandle* handle, CERTCrlHeadNode** nodes, int type) 739 { 740 CERTCrlHeadNode* head; 741 PLArenaPool* arena = NULL; 742 SECStatus rv; 743 744 *nodes = NULL; 745 746 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 747 if (arena == NULL) { 748 return SECFailure; 749 } 750 751 /* build a head structure */ 752 head = (CERTCrlHeadNode*)PORT_ArenaAlloc(arena, sizeof(CERTCrlHeadNode)); 753 head->arena = arena; 754 head->first = NULL; 755 head->last = NULL; 756 head->dbhandle = handle; 757 758 /* Look up the proper crl types */ 759 *nodes = head; 760 761 rv = PK11_LookupCrls(head, type, NULL); 762 763 if (rv != SECSuccess) { 764 if (arena) { 765 PORT_FreeArena(arena, PR_FALSE); 766 *nodes = NULL; 767 } 768 } 769 770 return rv; 771 } 772 773 /* These functions simply return the address of the above-declared templates. 774 ** This is necessary for Windows DLLs. Sigh. 775 */ 776 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_IssuerAndSNTemplate) 777 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CrlTemplate) 778 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedCrlTemplate) 779 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SetOfSignedCrlTemplate) 780 781 /* CRL cache code starts here */ 782 783 /* constructor */ 784 static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl, 785 CRLOrigin origin); 786 /* destructor */ 787 static SECStatus CachedCrl_Destroy(CachedCrl* crl); 788 789 /* create hash table of CRL entries */ 790 static SECStatus CachedCrl_Populate(CachedCrl* crlobject); 791 792 /* empty the cache content */ 793 static SECStatus CachedCrl_Depopulate(CachedCrl* crl); 794 795 /* are these CRLs the same, as far as the cache is concerned ? 796 Or are they the same token object, but with different DER ? */ 797 798 static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe, 799 PRBool* isUpdated); 800 801 /* create a DPCache object */ 802 static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer, 803 const SECItem* subject, SECItem* dp); 804 805 /* destructor for CRL DPCache object */ 806 static SECStatus DPCache_Destroy(CRLDPCache* cache); 807 808 /* add a new CRL object to the dynamic array of CRLs of the DPCache, and 809 returns the cached CRL object . Needs write access to DPCache. */ 810 static SECStatus DPCache_AddCRL(CRLDPCache* cache, CachedCrl* crl, 811 PRBool* added); 812 813 /* fetch the CRL for this DP from the PKCS#11 tokens */ 814 static SECStatus DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate, 815 void* wincx); 816 817 /* update the content of the CRL cache, including fetching of CRLs, and 818 reprocessing with specified issuer and date */ 819 static SECStatus DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate* issuer, 820 PRBool readlocked, PRTime vfdate, 821 void* wincx); 822 823 /* returns true if there are CRLs from PKCS#11 slots */ 824 static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache); 825 826 /* remove CRL at offset specified */ 827 static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset); 828 829 /* Pick best CRL to use . needs write access */ 830 static SECStatus DPCache_SelectCRL(CRLDPCache* cache); 831 832 /* create an issuer cache object (per CA subject ) */ 833 static SECStatus IssuerCache_Create(CRLIssuerCache** returned, 834 CERTCertificate* issuer, 835 const SECItem* subject, const SECItem* dp); 836 837 /* destructor for CRL IssuerCache object */ 838 SECStatus IssuerCache_Destroy(CRLIssuerCache* cache); 839 840 /* add a DPCache to the issuer cache */ 841 static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache, 842 CERTCertificate* issuer, 843 const SECItem* subject, const SECItem* dp, 844 CRLDPCache** newdpc); 845 846 /* get a particular DPCache object from an IssuerCache */ 847 static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache, 848 const SECItem* dp); 849 850 /* 851 ** Pre-allocator hash allocator ops. 852 */ 853 854 /* allocate memory for hash table */ 855 static void* PR_CALLBACK 856 PreAllocTable(void* pool, PRSize size) 857 { 858 PreAllocator* alloc = (PreAllocator*)pool; 859 PORT_Assert(alloc); 860 if (!alloc) { 861 /* no allocator, or buffer full */ 862 return NULL; 863 } 864 if (size > (alloc->len - alloc->used)) { 865 /* initial buffer full, let's use the arena */ 866 alloc->extra += size; 867 return PORT_ArenaAlloc(alloc->arena, size); 868 } 869 /* use the initial buffer */ 870 alloc->used += size; 871 return (char*)alloc->data + alloc->used - size; 872 } 873 874 /* free hash table memory. 875 Individual PreAllocator elements cannot be freed, so this is a no-op. */ 876 static void PR_CALLBACK 877 PreFreeTable(void* pool, void* item) 878 { 879 } 880 881 /* allocate memory for hash table */ 882 static PLHashEntry* PR_CALLBACK 883 PreAllocEntry(void* pool, const void* key) 884 { 885 return PreAllocTable(pool, sizeof(PLHashEntry)); 886 } 887 888 /* free hash table entry. 889 Individual PreAllocator elements cannot be freed, so this is a no-op. */ 890 static void PR_CALLBACK 891 PreFreeEntry(void* pool, PLHashEntry* he, PRUintn flag) 892 { 893 } 894 895 /* methods required for PL hash table functions */ 896 static PLHashAllocOps preAllocOps = { PreAllocTable, PreFreeTable, 897 PreAllocEntry, PreFreeEntry }; 898 899 /* destructor for PreAllocator object */ 900 void 901 PreAllocator_Destroy(PreAllocator* allocator) 902 { 903 if (!allocator) { 904 return; 905 } 906 if (allocator->arena) { 907 PORT_FreeArena(allocator->arena, PR_TRUE); 908 } 909 } 910 911 /* constructor for PreAllocator object */ 912 PreAllocator* 913 PreAllocator_Create(PRSize size) 914 { 915 PLArenaPool* arena = NULL; 916 PreAllocator* prebuffer = NULL; 917 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 918 if (!arena) { 919 return NULL; 920 } 921 prebuffer = (PreAllocator*)PORT_ArenaZAlloc(arena, sizeof(PreAllocator)); 922 if (!prebuffer) { 923 PORT_FreeArena(arena, PR_TRUE); 924 return NULL; 925 } 926 prebuffer->arena = arena; 927 928 if (size) { 929 prebuffer->len = size; 930 prebuffer->data = PORT_ArenaAlloc(arena, size); 931 if (!prebuffer->data) { 932 PORT_FreeArena(arena, PR_TRUE); 933 return NULL; 934 } 935 } 936 return prebuffer; 937 } 938 939 /* global Named CRL cache object */ 940 static NamedCRLCache namedCRLCache = { NULL, NULL }; 941 942 /* global CRL cache object */ 943 static CRLCache crlcache = { NULL, NULL }; 944 945 /* initial state is off */ 946 static PRBool crlcache_initialized = PR_FALSE; 947 948 PRTime CRLCache_Empty_TokenFetch_Interval = 60 * 1000000; /* how often 949 to query the tokens for CRL objects, in order to discover new objects, if 950 the cache does not contain any token CRLs . In microseconds */ 951 952 PRTime CRLCache_TokenRefetch_Interval = 600 * 1000000; /* how often 953 to query the tokens for CRL objects, in order to discover new objects, if 954 the cache already contains token CRLs In microseconds */ 955 956 PRTime CRLCache_ExistenceCheck_Interval = 60 * 1000000; /* how often to check 957 if a token CRL object still exists. In microseconds */ 958 959 /* this function is called at NSS initialization time */ 960 SECStatus 961 InitCRLCache(void) 962 { 963 if (PR_FALSE == crlcache_initialized) { 964 PORT_Assert(NULL == crlcache.lock); 965 PORT_Assert(NULL == crlcache.issuers); 966 PORT_Assert(NULL == namedCRLCache.lock); 967 PORT_Assert(NULL == namedCRLCache.entries); 968 if (crlcache.lock || crlcache.issuers || namedCRLCache.lock || 969 namedCRLCache.entries) { 970 /* CRL cache already partially initialized */ 971 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 972 return SECFailure; 973 } 974 #ifdef GLOBAL_RWLOCK 975 crlcache.lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL); 976 #else 977 crlcache.lock = PR_NewLock(); 978 #endif 979 namedCRLCache.lock = PR_NewLock(); 980 crlcache.issuers = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare, 981 PL_CompareValues, NULL, NULL); 982 namedCRLCache.entries = PL_NewHashTable( 983 0, SECITEM_Hash, SECITEM_HashCompare, PL_CompareValues, NULL, NULL); 984 if (!crlcache.lock || !namedCRLCache.lock || !crlcache.issuers || 985 !namedCRLCache.entries) { 986 if (crlcache.lock) { 987 #ifdef GLOBAL_RWLOCK 988 NSSRWLock_Destroy(crlcache.lock); 989 #else 990 PR_DestroyLock(crlcache.lock); 991 #endif 992 crlcache.lock = NULL; 993 } 994 if (namedCRLCache.lock) { 995 PR_DestroyLock(namedCRLCache.lock); 996 namedCRLCache.lock = NULL; 997 } 998 if (crlcache.issuers) { 999 PL_HashTableDestroy(crlcache.issuers); 1000 crlcache.issuers = NULL; 1001 } 1002 if (namedCRLCache.entries) { 1003 PL_HashTableDestroy(namedCRLCache.entries); 1004 namedCRLCache.entries = NULL; 1005 } 1006 1007 return SECFailure; 1008 } 1009 crlcache_initialized = PR_TRUE; 1010 return SECSuccess; 1011 } else { 1012 PORT_Assert(crlcache.lock); 1013 PORT_Assert(crlcache.issuers); 1014 if ((NULL == crlcache.lock) || (NULL == crlcache.issuers)) { 1015 /* CRL cache not fully initialized */ 1016 return SECFailure; 1017 } else { 1018 /* CRL cache already initialized */ 1019 return SECSuccess; 1020 } 1021 } 1022 } 1023 1024 /* destructor for CRL DPCache object */ 1025 static SECStatus 1026 DPCache_Destroy(CRLDPCache* cache) 1027 { 1028 PRUint32 i = 0; 1029 PORT_Assert(cache); 1030 if (!cache) { 1031 PORT_Assert(0); 1032 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1033 return SECFailure; 1034 } 1035 if (cache->lock) { 1036 #ifdef DPC_RWLOCK 1037 NSSRWLock_Destroy(cache->lock); 1038 #else 1039 PR_DestroyLock(cache->lock); 1040 #endif 1041 } else { 1042 PORT_Assert(0); 1043 return SECFailure; 1044 } 1045 /* destroy all our CRL objects */ 1046 for (i = 0; i < cache->ncrls; i++) { 1047 if (!cache->crls || !cache->crls[i] || 1048 SECSuccess != CachedCrl_Destroy(cache->crls[i])) { 1049 return SECFailure; 1050 } 1051 } 1052 /* free the array of CRLs */ 1053 if (cache->crls) { 1054 PORT_Free(cache->crls); 1055 } 1056 /* destroy the cert */ 1057 if (cache->issuerDERCert) { 1058 SECITEM_FreeItem(cache->issuerDERCert, PR_TRUE); 1059 } 1060 /* free the subject */ 1061 if (cache->subject) { 1062 SECITEM_FreeItem(cache->subject, PR_TRUE); 1063 } 1064 /* free the distribution points */ 1065 if (cache->distributionPoint) { 1066 SECITEM_FreeItem(cache->distributionPoint, PR_TRUE); 1067 } 1068 PORT_Free(cache); 1069 return SECSuccess; 1070 } 1071 1072 /* destructor for CRL IssuerCache object */ 1073 SECStatus 1074 IssuerCache_Destroy(CRLIssuerCache* cache) 1075 { 1076 PORT_Assert(cache); 1077 if (!cache) { 1078 PORT_Assert(0); 1079 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1080 return SECFailure; 1081 } 1082 #ifdef XCRL 1083 if (cache->lock) { 1084 NSSRWLock_Destroy(cache->lock); 1085 } else { 1086 PORT_Assert(0); 1087 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1088 return SECFailure; 1089 } 1090 if (cache->issuer) { 1091 CERT_DestroyCertificate(cache->issuer); 1092 } 1093 #endif 1094 /* free the subject */ 1095 if (cache->subject) { 1096 SECITEM_FreeItem(cache->subject, PR_TRUE); 1097 } 1098 if (SECSuccess != DPCache_Destroy(cache->dpp)) { 1099 PORT_Assert(0); 1100 return SECFailure; 1101 } 1102 PORT_Free(cache); 1103 return SECSuccess; 1104 } 1105 1106 /* create a named CRL entry object */ 1107 static SECStatus 1108 NamedCRLCacheEntry_Create(NamedCRLCacheEntry** returned) 1109 { 1110 NamedCRLCacheEntry* entry = NULL; 1111 if (!returned) { 1112 PORT_Assert(0); 1113 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1114 return SECFailure; 1115 } 1116 *returned = NULL; 1117 entry = (NamedCRLCacheEntry*)PORT_ZAlloc(sizeof(NamedCRLCacheEntry)); 1118 if (!entry) { 1119 return SECFailure; 1120 } 1121 *returned = entry; 1122 return SECSuccess; 1123 } 1124 1125 /* destroy a named CRL entry object */ 1126 static SECStatus 1127 NamedCRLCacheEntry_Destroy(NamedCRLCacheEntry* entry) 1128 { 1129 if (!entry) { 1130 PORT_Assert(0); 1131 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1132 return SECFailure; 1133 } 1134 if (entry->crl) { 1135 /* named CRL cache owns DER memory */ 1136 SECITEM_ZfreeItem(entry->crl, PR_TRUE); 1137 } 1138 if (entry->canonicalizedName) { 1139 SECITEM_FreeItem(entry->canonicalizedName, PR_TRUE); 1140 } 1141 PORT_Free(entry); 1142 return SECSuccess; 1143 } 1144 1145 /* callback function used in hash table destructor */ 1146 static PRIntn PR_CALLBACK 1147 FreeIssuer(PLHashEntry* he, PRIntn i, void* arg) 1148 { 1149 CRLIssuerCache* issuer = NULL; 1150 SECStatus* rv = (SECStatus*)arg; 1151 1152 PORT_Assert(he); 1153 if (!he) { 1154 return HT_ENUMERATE_NEXT; 1155 } 1156 issuer = (CRLIssuerCache*)he->value; 1157 PORT_Assert(issuer); 1158 if (issuer) { 1159 if (SECSuccess != IssuerCache_Destroy(issuer)) { 1160 PORT_Assert(rv); 1161 if (rv) { 1162 *rv = SECFailure; 1163 } 1164 return HT_ENUMERATE_NEXT; 1165 } 1166 } 1167 return HT_ENUMERATE_NEXT; 1168 } 1169 1170 /* callback function used in hash table destructor */ 1171 static PRIntn PR_CALLBACK 1172 FreeNamedEntries(PLHashEntry* he, PRIntn i, void* arg) 1173 { 1174 NamedCRLCacheEntry* entry = NULL; 1175 SECStatus* rv = (SECStatus*)arg; 1176 1177 PORT_Assert(he); 1178 if (!he) { 1179 return HT_ENUMERATE_NEXT; 1180 } 1181 entry = (NamedCRLCacheEntry*)he->value; 1182 PORT_Assert(entry); 1183 if (entry) { 1184 if (SECSuccess != NamedCRLCacheEntry_Destroy(entry)) { 1185 PORT_Assert(rv); 1186 if (rv) { 1187 *rv = SECFailure; 1188 } 1189 return HT_ENUMERATE_NEXT; 1190 } 1191 } 1192 return HT_ENUMERATE_NEXT; 1193 } 1194 1195 /* needs to be called at NSS shutdown time 1196 This will destroy the global CRL cache, including 1197 - the hash table of issuer cache objects 1198 - the issuer cache objects 1199 - DPCache objects in issuer cache objects */ 1200 SECStatus 1201 ShutdownCRLCache(void) 1202 { 1203 SECStatus rv = SECSuccess; 1204 if (PR_FALSE == crlcache_initialized && !crlcache.lock && 1205 !crlcache.issuers) { 1206 /* CRL cache has already been shut down */ 1207 return SECSuccess; 1208 } 1209 if (PR_TRUE == crlcache_initialized && 1210 (!crlcache.lock || !crlcache.issuers || !namedCRLCache.lock || 1211 !namedCRLCache.entries)) { 1212 /* CRL cache has partially been shut down */ 1213 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1214 return SECFailure; 1215 } 1216 /* empty the CRL cache */ 1217 /* free the issuers */ 1218 PL_HashTableEnumerateEntries(crlcache.issuers, &FreeIssuer, &rv); 1219 /* free the hash table of issuers */ 1220 PL_HashTableDestroy(crlcache.issuers); 1221 crlcache.issuers = NULL; 1222 /* free the global lock */ 1223 #ifdef GLOBAL_RWLOCK 1224 NSSRWLock_Destroy(crlcache.lock); 1225 #else 1226 PR_DestroyLock(crlcache.lock); 1227 #endif 1228 crlcache.lock = NULL; 1229 1230 /* empty the named CRL cache. This must be done after freeing the CRL 1231 * cache, since some CRLs in this cache are in the memory for the other */ 1232 /* free the entries */ 1233 PL_HashTableEnumerateEntries(namedCRLCache.entries, &FreeNamedEntries, &rv); 1234 /* free the hash table of issuers */ 1235 PL_HashTableDestroy(namedCRLCache.entries); 1236 namedCRLCache.entries = NULL; 1237 /* free the global lock */ 1238 PR_DestroyLock(namedCRLCache.lock); 1239 namedCRLCache.lock = NULL; 1240 1241 crlcache_initialized = PR_FALSE; 1242 return rv; 1243 } 1244 1245 /* add a new CRL object to the dynamic array of CRLs of the DPCache, and 1246 returns the cached CRL object . Needs write access to DPCache. */ 1247 static SECStatus 1248 DPCache_AddCRL(CRLDPCache* cache, CachedCrl* newcrl, PRBool* added) 1249 { 1250 CachedCrl** newcrls = NULL; 1251 PRUint32 i = 0; 1252 PORT_Assert(cache); 1253 PORT_Assert(newcrl); 1254 PORT_Assert(added); 1255 if (!cache || !newcrl || !added) { 1256 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1257 return SECFailure; 1258 } 1259 1260 *added = PR_FALSE; 1261 /* before adding a new CRL, check if it is a duplicate */ 1262 for (i = 0; i < cache->ncrls; i++) { 1263 CachedCrl* existing = NULL; 1264 SECStatus rv = SECSuccess; 1265 PRBool dupe = PR_FALSE, updated = PR_FALSE; 1266 if (!cache->crls) { 1267 PORT_Assert(0); 1268 return SECFailure; 1269 } 1270 existing = cache->crls[i]; 1271 if (!existing) { 1272 PORT_Assert(0); 1273 return SECFailure; 1274 } 1275 rv = CachedCrl_Compare(existing, newcrl, &dupe, &updated); 1276 if (SECSuccess != rv) { 1277 PORT_Assert(0); 1278 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1279 return SECFailure; 1280 } 1281 if (PR_TRUE == dupe) { 1282 /* dupe */ 1283 PORT_SetError(SEC_ERROR_CRL_ALREADY_EXISTS); 1284 return SECSuccess; 1285 } 1286 if (PR_TRUE == updated) { 1287 /* this token CRL is in the same slot and has the same object ID, 1288 but different content. We need to remove the old object */ 1289 if (SECSuccess != DPCache_RemoveCRL(cache, i)) { 1290 PORT_Assert(0); 1291 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1292 return PR_FALSE; 1293 } 1294 } 1295 } 1296 1297 newcrls = (CachedCrl**)PORT_Realloc(cache->crls, (cache->ncrls + 1) * sizeof(CachedCrl*)); 1298 if (!newcrls) { 1299 return SECFailure; 1300 } 1301 cache->crls = newcrls; 1302 cache->ncrls++; 1303 cache->crls[cache->ncrls - 1] = newcrl; 1304 *added = PR_TRUE; 1305 return SECSuccess; 1306 } 1307 1308 /* remove CRL at offset specified */ 1309 static SECStatus 1310 DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset) 1311 { 1312 CachedCrl* acrl = NULL; 1313 PORT_Assert(cache); 1314 if (!cache || (!cache->crls) || (!(offset < cache->ncrls))) { 1315 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1316 return SECFailure; 1317 } 1318 acrl = cache->crls[offset]; 1319 PORT_Assert(acrl); 1320 if (!acrl) { 1321 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1322 return SECFailure; 1323 } 1324 cache->crls[offset] = cache->crls[cache->ncrls - 1]; 1325 cache->crls[cache->ncrls - 1] = NULL; 1326 cache->ncrls--; 1327 if (cache->selected == acrl) { 1328 cache->selected = NULL; 1329 } 1330 if (SECSuccess != CachedCrl_Destroy(acrl)) { 1331 PORT_Assert(0); 1332 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1333 return SECFailure; 1334 } 1335 return SECSuccess; 1336 } 1337 1338 /* check whether a CRL object stored in a PKCS#11 token still exists in 1339 that token . This has to be efficient (the entire CRL value cannot be 1340 transferred accross the token boundaries), so this is accomplished by 1341 simply fetching the subject attribute and making sure it hasn't changed . 1342 Note that technically, the CRL object could have been replaced with a new 1343 PKCS#11 object of the same ID and subject (which actually happens in 1344 softoken), but this function has no way of knowing that the object 1345 value changed, since CKA_VALUE isn't checked. */ 1346 static PRBool 1347 TokenCRLStillExists(CERTSignedCrl* crl) 1348 { 1349 NSSItem newsubject; 1350 SECItem subject; 1351 CK_ULONG crl_class; 1352 PRStatus status; 1353 PK11SlotInfo* slot = NULL; 1354 nssCryptokiObject instance; 1355 NSSArena* arena; 1356 PRBool xstatus = PR_TRUE; 1357 SECItem* oldSubject = NULL; 1358 1359 PORT_Assert(crl); 1360 if (!crl) { 1361 return PR_FALSE; 1362 } 1363 slot = crl->slot; 1364 PORT_Assert(crl->slot); 1365 if (!slot) { 1366 return PR_FALSE; 1367 } 1368 oldSubject = &crl->crl.derName; 1369 PORT_Assert(oldSubject); 1370 if (!oldSubject) { 1371 return PR_FALSE; 1372 } 1373 1374 /* query subject and type attributes in order to determine if the 1375 object has been deleted */ 1376 1377 /* first, make an nssCryptokiObject */ 1378 instance.handle = crl->pkcs11ID; 1379 PORT_Assert(instance.handle); 1380 if (!instance.handle) { 1381 return PR_FALSE; 1382 } 1383 instance.token = PK11Slot_GetNSSToken(slot); 1384 PORT_Assert(instance.token); 1385 if (!instance.token) { 1386 return PR_FALSE; 1387 } 1388 instance.isTokenObject = PR_TRUE; 1389 instance.label = NULL; 1390 1391 arena = NSSArena_Create(); 1392 PORT_Assert(arena); 1393 if (!arena) { 1394 (void)nssToken_Destroy(instance.token); 1395 return PR_FALSE; 1396 } 1397 1398 status = 1399 nssCryptokiCRL_GetAttributes(&instance, NULL, /* XXX sessionOpt */ 1400 arena, NULL, &newsubject, /* subject */ 1401 &crl_class, /* class */ 1402 NULL, NULL); 1403 if (PR_SUCCESS == status) { 1404 subject.data = newsubject.data; 1405 subject.len = newsubject.size; 1406 if (SECITEM_CompareItem(oldSubject, &subject) != SECEqual) { 1407 xstatus = PR_FALSE; 1408 } 1409 if (CKO_NSS_CRL != crl_class) { 1410 xstatus = PR_FALSE; 1411 } 1412 } else { 1413 xstatus = PR_FALSE; 1414 } 1415 NSSArena_Destroy(arena); 1416 (void)nssToken_Destroy(instance.token); 1417 return xstatus; 1418 } 1419 1420 /* verify the signature of a CRL against its issuer at a given date */ 1421 static SECStatus 1422 CERT_VerifyCRL(CERTSignedCrl* crlobject, CERTCertificate* issuer, PRTime vfdate, 1423 void* wincx) 1424 { 1425 return CERT_VerifySignedData(&crlobject->signatureWrap, issuer, vfdate, 1426 wincx); 1427 } 1428 1429 /* verify a CRL and update cache state */ 1430 static SECStatus 1431 CachedCrl_Verify(CRLDPCache* cache, CachedCrl* crlobject, PRTime vfdate, 1432 void* wincx) 1433 { 1434 /* Check if it is an invalid CRL 1435 if we got a bad CRL, we want to cache it in order to avoid 1436 subsequent fetches of this same identical bad CRL. We set 1437 the cache to the invalid state to ensure that all certs on this 1438 DP are considered to have unknown status from now on. The cache 1439 object will remain in this state until the bad CRL object 1440 is removed from the token it was fetched from. If the cause 1441 of the failure is that we didn't have the issuer cert to 1442 verify the signature, this state can be cleared when 1443 the issuer certificate becomes available if that causes the 1444 signature to verify */ 1445 1446 if (!cache || !crlobject) { 1447 PORT_Assert(0); 1448 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1449 return SECFailure; 1450 } 1451 if (PR_TRUE == GetOpaqueCRLFields(crlobject->crl)->decodingError) { 1452 crlobject->sigChecked = PR_TRUE; /* we can never verify a CRL 1453 with bogus DER. Mark it checked so we won't try again */ 1454 PORT_SetError(SEC_ERROR_BAD_DER); 1455 return SECSuccess; 1456 } else { 1457 SECStatus signstatus = SECFailure; 1458 if (cache->issuerDERCert) { 1459 CERTCertificate* issuer = CERT_NewTempCertificate( 1460 cache->dbHandle, cache->issuerDERCert, NULL, PR_FALSE, PR_TRUE); 1461 1462 if (issuer) { 1463 signstatus = 1464 CERT_VerifyCRL(crlobject->crl, issuer, vfdate, wincx); 1465 CERT_DestroyCertificate(issuer); 1466 } 1467 } 1468 if (SECSuccess != signstatus) { 1469 if (!cache->issuerDERCert) { 1470 /* we tried to verify without an issuer cert . This is 1471 because this CRL came through a call to SEC_FindCrlByName. 1472 So, we don't cache this verification failure. We'll try 1473 to verify the CRL again when a certificate from that issuer 1474 becomes available */ 1475 } else { 1476 crlobject->sigChecked = PR_TRUE; 1477 } 1478 PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE); 1479 return SECSuccess; 1480 } else { 1481 crlobject->sigChecked = PR_TRUE; 1482 crlobject->sigValid = PR_TRUE; 1483 } 1484 } 1485 1486 return SECSuccess; 1487 } 1488 1489 /* fetch the CRLs for this DP from the PKCS#11 tokens */ 1490 static SECStatus 1491 DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate, void* wincx) 1492 { 1493 SECStatus rv = SECSuccess; 1494 CERTCrlHeadNode head; 1495 if (!cache) { 1496 PORT_Assert(0); 1497 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1498 return SECFailure; 1499 } 1500 /* first, initialize list */ 1501 memset(&head, 0, sizeof(head)); 1502 head.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1503 rv = pk11_RetrieveCrls(&head, cache->subject, wincx); 1504 1505 /* if this function fails, something very wrong happened, such as an out 1506 of memory error during CRL decoding. We don't want to proceed and must 1507 mark the cache object invalid */ 1508 if (SECFailure == rv) { 1509 /* fetch failed, add error bit */ 1510 cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED; 1511 } else { 1512 /* fetch was successful, clear this error bit */ 1513 cache->invalid &= (~CRL_CACHE_LAST_FETCH_FAILED); 1514 } 1515 1516 /* add any CRLs found to our array */ 1517 if (SECSuccess == rv) { 1518 CERTCrlNode* crlNode = NULL; 1519 1520 for (crlNode = head.first; crlNode; crlNode = crlNode->next) { 1521 CachedCrl* returned = NULL; 1522 CERTSignedCrl* crlobject = crlNode->crl; 1523 if (!crlobject) { 1524 PORT_Assert(0); 1525 continue; 1526 } 1527 rv = CachedCrl_Create(&returned, crlobject, CRL_OriginToken); 1528 if (SECSuccess == rv) { 1529 PRBool added = PR_FALSE; 1530 rv = DPCache_AddCRL(cache, returned, &added); 1531 if (PR_TRUE != added) { 1532 rv = CachedCrl_Destroy(returned); 1533 returned = NULL; 1534 } else if (vfdate) { 1535 rv = CachedCrl_Verify(cache, returned, vfdate, wincx); 1536 } 1537 } else { 1538 /* not enough memory to add the CRL to the cache. mark it 1539 invalid so we will try again . */ 1540 cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED; 1541 } 1542 if (SECFailure == rv) { 1543 break; 1544 } 1545 } 1546 } 1547 1548 if (head.arena) { 1549 CERTCrlNode* crlNode = NULL; 1550 /* clean up the CRL list in case we got a partial one 1551 during a failed fetch */ 1552 for (crlNode = head.first; crlNode; crlNode = crlNode->next) { 1553 if (crlNode->crl) { 1554 SEC_DestroyCrl(crlNode->crl); /* free the CRL. Either it got 1555 added to the cache and the refcount got bumped, or not, and 1556 thus we need to free its RAM */ 1557 } 1558 } 1559 PORT_FreeArena(head.arena, PR_FALSE); /* destroy CRL list */ 1560 } 1561 1562 return rv; 1563 } 1564 1565 static SECStatus 1566 CachedCrl_GetEntry(CachedCrl* crl, const SECItem* sn, CERTCrlEntry** returned) 1567 { 1568 CERTCrlEntry* acrlEntry; 1569 1570 PORT_Assert(crl); 1571 PORT_Assert(crl->entries); 1572 PORT_Assert(sn); 1573 PORT_Assert(returned); 1574 if (!crl || !sn || !returned || !crl->entries) { 1575 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1576 return SECFailure; 1577 } 1578 acrlEntry = PL_HashTableLookup(crl->entries, (void*)sn); 1579 if (acrlEntry) { 1580 *returned = acrlEntry; 1581 } else { 1582 *returned = NULL; 1583 } 1584 return SECSuccess; 1585 } 1586 1587 /* check if a particular SN is in the CRL cache and return its entry */ 1588 dpcacheStatus 1589 DPCache_Lookup(CRLDPCache* cache, const SECItem* sn, CERTCrlEntry** returned) 1590 { 1591 SECStatus rv; 1592 if (!cache || !sn || !returned) { 1593 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1594 /* no cache or SN to look up, or no way to return entry */ 1595 return dpcacheCallerError; 1596 } 1597 *returned = NULL; 1598 if (0 != cache->invalid) { 1599 /* the cache contains a bad CRL, or there was a CRL fetching error. */ 1600 PORT_SetError(SEC_ERROR_CRL_INVALID); 1601 return dpcacheInvalidCacheError; 1602 } 1603 if (!cache->selected) { 1604 /* no CRL means no entry to return. This is OK, except for 1605 * NIST policy */ 1606 return dpcacheEmpty; 1607 } 1608 rv = CachedCrl_GetEntry(cache->selected, sn, returned); 1609 if (SECSuccess != rv) { 1610 return dpcacheLookupError; 1611 } else { 1612 if (*returned) { 1613 return dpcacheFoundEntry; 1614 } else { 1615 return dpcacheNoEntry; 1616 } 1617 } 1618 } 1619 1620 #if defined(DPC_RWLOCK) 1621 1622 #define DPCache_LockWrite() \ 1623 { \ 1624 if (readlocked) { \ 1625 NSSRWLock_UnlockRead(cache->lock); \ 1626 } \ 1627 NSSRWLock_LockWrite(cache->lock); \ 1628 } 1629 1630 #define DPCache_UnlockWrite() \ 1631 { \ 1632 if (readlocked) { \ 1633 NSSRWLock_LockRead(cache->lock); \ 1634 } \ 1635 NSSRWLock_UnlockWrite(cache->lock); \ 1636 } 1637 1638 #else 1639 1640 /* with a global lock, we are always locked for read before we need write 1641 access, so do nothing */ 1642 1643 #define DPCache_LockWrite() \ 1644 { \ 1645 } 1646 1647 #define DPCache_UnlockWrite() \ 1648 { \ 1649 } 1650 1651 #endif 1652 1653 /* update the content of the CRL cache, including fetching of CRLs, and 1654 reprocessing with specified issuer and date . We are always holding 1655 either the read or write lock on DPCache upon entry. */ 1656 static SECStatus 1657 DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate* issuer, 1658 PRBool readlocked, PRTime vfdate, void* wincx) 1659 { 1660 /* Update the CRLDPCache now. We don't cache token CRL lookup misses 1661 yet, as we have no way of getting notified of new PKCS#11 object 1662 creation that happens in a token */ 1663 SECStatus rv = SECSuccess; 1664 PRUint32 i = 0; 1665 PRBool forcedrefresh = PR_FALSE; 1666 PRBool dirty = PR_FALSE; /* whether something was changed in the 1667 cache state during this update cycle */ 1668 PRBool hastokenCRLs = PR_FALSE; 1669 PRTime now = 0; 1670 PRTime lastfetch = 0; 1671 PRBool mustunlock = PR_FALSE; 1672 1673 if (!cache) { 1674 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1675 return SECFailure; 1676 } 1677 1678 /* first, make sure we have obtained all the CRLs we need. 1679 We do an expensive token fetch in the following cases : 1680 1) cache is empty because no fetch was ever performed yet 1681 2) cache is explicitly set to refresh state 1682 3) cache is in invalid state because last fetch failed 1683 4) cache contains no token CRLs, and it's been more than one minute 1684 since the last fetch 1685 5) cache contains token CRLs, and it's been more than 10 minutes since 1686 the last fetch 1687 */ 1688 forcedrefresh = cache->refresh; 1689 lastfetch = cache->lastfetch; 1690 if (PR_TRUE != forcedrefresh && 1691 (!(cache->invalid & CRL_CACHE_LAST_FETCH_FAILED))) { 1692 now = PR_Now(); 1693 hastokenCRLs = DPCache_HasTokenCRLs(cache); 1694 } 1695 if ((0 == lastfetch) || 1696 1697 (PR_TRUE == forcedrefresh) || 1698 1699 (cache->invalid & CRL_CACHE_LAST_FETCH_FAILED) || 1700 1701 ((PR_FALSE == hastokenCRLs) && 1702 ((now - cache->lastfetch > CRLCache_Empty_TokenFetch_Interval) || 1703 (now < cache->lastfetch))) || 1704 1705 ((PR_TRUE == hastokenCRLs) && 1706 ((now - cache->lastfetch > CRLCache_TokenRefetch_Interval) || 1707 (now < cache->lastfetch)))) { 1708 /* the cache needs to be refreshed, and/or we had zero CRL for this 1709 DP. Try to get one from PKCS#11 tokens */ 1710 DPCache_LockWrite(); 1711 /* check if another thread updated before us, and skip update if so */ 1712 if (lastfetch == cache->lastfetch) { 1713 /* we are the first */ 1714 rv = DPCache_FetchFromTokens(cache, vfdate, wincx); 1715 if (PR_TRUE == cache->refresh) { 1716 cache->refresh = PR_FALSE; /* clear refresh state */ 1717 } 1718 dirty = PR_TRUE; 1719 cache->lastfetch = PR_Now(); 1720 } 1721 DPCache_UnlockWrite(); 1722 } 1723 1724 /* now, make sure we have no extraneous CRLs (deleted token objects) 1725 we'll do this inexpensive existence check either 1726 1) if there was a token object fetch 1727 2) every minute */ 1728 if ((PR_TRUE != dirty) && (!now)) { 1729 now = PR_Now(); 1730 } 1731 if ((PR_TRUE == dirty) || 1732 ((now - cache->lastcheck > CRLCache_ExistenceCheck_Interval) || 1733 (now < cache->lastcheck))) { 1734 PRTime lastcheck = cache->lastcheck; 1735 mustunlock = PR_FALSE; 1736 /* check if all CRLs still exist */ 1737 for (i = 0; (i < cache->ncrls); i++) { 1738 CachedCrl* savcrl = cache->crls[i]; 1739 if ((!savcrl) || (savcrl && CRL_OriginToken != savcrl->origin)) { 1740 /* we only want to check token CRLs */ 1741 continue; 1742 } 1743 if ((PR_TRUE != TokenCRLStillExists(savcrl->crl))) { 1744 1745 /* this CRL is gone */ 1746 if (PR_TRUE != mustunlock) { 1747 DPCache_LockWrite(); 1748 mustunlock = PR_TRUE; 1749 } 1750 /* first, we need to check if another thread did an update 1751 before we did */ 1752 if (lastcheck == cache->lastcheck) { 1753 /* the CRL is gone. And we are the one to do the update */ 1754 DPCache_RemoveCRL(cache, i); 1755 dirty = PR_TRUE; 1756 } 1757 /* stay locked here intentionally so we do all the other 1758 updates in this thread for the remaining CRLs */ 1759 } 1760 } 1761 if (PR_TRUE == mustunlock) { 1762 cache->lastcheck = PR_Now(); 1763 DPCache_UnlockWrite(); 1764 mustunlock = PR_FALSE; 1765 } 1766 } 1767 1768 /* add issuer certificate if it was previously unavailable */ 1769 if (issuer && (NULL == cache->issuerDERCert) && 1770 (SECSuccess == CERT_CheckCertUsage(issuer, KU_CRL_SIGN))) { 1771 /* if we didn't have a valid issuer cert yet, but we do now. add it */ 1772 DPCache_LockWrite(); 1773 if (!cache->issuerDERCert) { 1774 dirty = PR_TRUE; 1775 cache->dbHandle = issuer->dbhandle; 1776 cache->issuerDERCert = SECITEM_DupItem(&issuer->derCert); 1777 } 1778 DPCache_UnlockWrite(); 1779 } 1780 1781 /* verify CRLs that couldn't be checked when inserted into the cache 1782 because the issuer cert or a verification date was unavailable. 1783 These are CRLs that were inserted into the cache through 1784 SEC_FindCrlByName, or through manual insertion, rather than through a 1785 certificate verification (CERT_CheckCRL) */ 1786 1787 if (cache->issuerDERCert && vfdate) { 1788 mustunlock = PR_FALSE; 1789 /* re-process all unverified CRLs */ 1790 for (i = 0; i < cache->ncrls; i++) { 1791 CachedCrl* savcrl = cache->crls[i]; 1792 if (!savcrl) { 1793 continue; 1794 } 1795 if (PR_TRUE != savcrl->sigChecked) { 1796 if (!mustunlock) { 1797 DPCache_LockWrite(); 1798 mustunlock = PR_TRUE; 1799 } 1800 /* first, we need to check if another thread updated 1801 it before we did, and abort if it has been modified since 1802 we acquired the lock. Make sure first that the CRL is still 1803 in the array at the same position */ 1804 if ((i < cache->ncrls) && (savcrl == cache->crls[i]) && 1805 (PR_TRUE != savcrl->sigChecked)) { 1806 /* the CRL is still there, unverified. Do it */ 1807 CachedCrl_Verify(cache, savcrl, vfdate, wincx); 1808 dirty = PR_TRUE; 1809 } 1810 /* stay locked here intentionally so we do all the other 1811 updates in this thread for the remaining CRLs */ 1812 } 1813 if (mustunlock && !dirty) { 1814 DPCache_UnlockWrite(); 1815 mustunlock = PR_FALSE; 1816 } 1817 } 1818 } 1819 1820 if (dirty || cache->mustchoose) { 1821 /* changes to the content of the CRL cache necessitate examining all 1822 CRLs for selection of the most appropriate one to cache */ 1823 if (!mustunlock) { 1824 DPCache_LockWrite(); 1825 mustunlock = PR_TRUE; 1826 } 1827 DPCache_SelectCRL(cache); 1828 cache->mustchoose = PR_FALSE; 1829 } 1830 if (mustunlock) 1831 DPCache_UnlockWrite(); 1832 1833 return rv; 1834 } 1835 1836 /* callback for qsort to sort by thisUpdate */ 1837 static int 1838 SortCRLsByThisUpdate(const void* arg1, const void* arg2) 1839 { 1840 PRTime timea, timeb; 1841 SECStatus rv = SECSuccess; 1842 CachedCrl *a, *b; 1843 1844 a = *(CachedCrl**)arg1; 1845 b = *(CachedCrl**)arg2; 1846 1847 if (!a || !b) { 1848 PORT_Assert(0); 1849 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1850 rv = SECFailure; 1851 } 1852 1853 if (SECSuccess == rv) { 1854 rv = DER_DecodeTimeChoice(&timea, &a->crl->crl.lastUpdate); 1855 } 1856 if (SECSuccess == rv) { 1857 rv = DER_DecodeTimeChoice(&timeb, &b->crl->crl.lastUpdate); 1858 } 1859 if (SECSuccess == rv) { 1860 if (timea > timeb) { 1861 return 1; /* a is better than b */ 1862 } 1863 if (timea < timeb) { 1864 return -1; /* a is not as good as b */ 1865 } 1866 } 1867 1868 /* if they are equal, or if all else fails, use pointer differences */ 1869 PORT_Assert(a != b); /* they should never be equal */ 1870 return a > b ? 1 : -1; 1871 } 1872 1873 /* callback for qsort to sort a set of disparate CRLs, some of which are 1874 invalid DER or failed signature check. 1875 1876 Validated CRLs are differentiated by thisUpdate . 1877 Validated CRLs are preferred over non-validated CRLs . 1878 Proper DER CRLs are preferred over non-DER data . 1879 */ 1880 static int 1881 SortImperfectCRLs(const void* arg1, const void* arg2) 1882 { 1883 CachedCrl *a, *b; 1884 1885 a = *(CachedCrl**)arg1; 1886 b = *(CachedCrl**)arg2; 1887 1888 if (!a || !b) { 1889 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1890 PORT_Assert(0); 1891 } else { 1892 PRBool aDecoded = PR_FALSE, bDecoded = PR_FALSE; 1893 if ((PR_TRUE == a->sigValid) && (PR_TRUE == b->sigValid)) { 1894 /* both CRLs have been validated, choose the latest one */ 1895 return SortCRLsByThisUpdate(arg1, arg2); 1896 } 1897 if (PR_TRUE == a->sigValid) { 1898 return 1; /* a is greater than b */ 1899 } 1900 if (PR_TRUE == b->sigValid) { 1901 return -1; /* a is not as good as b */ 1902 } 1903 aDecoded = GetOpaqueCRLFields(a->crl)->decodingError; 1904 bDecoded = GetOpaqueCRLFields(b->crl)->decodingError; 1905 /* neither CRL had its signature check pass */ 1906 if ((PR_FALSE == aDecoded) && (PR_FALSE == bDecoded)) { 1907 /* both CRLs are proper DER, choose the latest one */ 1908 return SortCRLsByThisUpdate(arg1, arg2); 1909 } 1910 if (PR_FALSE == aDecoded) { 1911 return 1; /* a is better than b */ 1912 } 1913 if (PR_FALSE == bDecoded) { 1914 return -1; /* a is not as good as b */ 1915 } 1916 /* both are invalid DER. sigh. */ 1917 } 1918 /* if they are equal, or if all else fails, use pointer differences */ 1919 PORT_Assert(a != b); /* they should never be equal */ 1920 return a > b ? 1 : -1; 1921 } 1922 1923 /* Pick best CRL to use . needs write access */ 1924 static SECStatus 1925 DPCache_SelectCRL(CRLDPCache* cache) 1926 { 1927 PRUint32 i; 1928 PRBool valid = PR_TRUE; 1929 CachedCrl* selected = NULL; 1930 1931 PORT_Assert(cache); 1932 if (!cache) { 1933 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1934 return SECFailure; 1935 } 1936 /* if any invalid CRL is present, then the CRL cache is 1937 considered invalid, for security reasons */ 1938 for (i = 0; i < cache->ncrls; i++) { 1939 if (!cache->crls[i] || !cache->crls[i]->sigChecked || 1940 !cache->crls[i]->sigValid) { 1941 valid = PR_FALSE; 1942 break; 1943 } 1944 } 1945 if (PR_TRUE == valid) { 1946 /* all CRLs are valid, clear this error */ 1947 cache->invalid &= (~CRL_CACHE_INVALID_CRLS); 1948 } else { 1949 /* some CRLs are invalid, set this error */ 1950 cache->invalid |= CRL_CACHE_INVALID_CRLS; 1951 } 1952 1953 if (cache->invalid) { 1954 /* cache is in an invalid state, so reset it */ 1955 if (cache->selected) { 1956 cache->selected = NULL; 1957 } 1958 /* also sort the CRLs imperfectly */ 1959 qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*), SortImperfectCRLs); 1960 return SECSuccess; 1961 } 1962 1963 if (cache->ncrls) { 1964 /* all CRLs are good, sort them by thisUpdate */ 1965 qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*), SortCRLsByThisUpdate); 1966 1967 /* pick the newest CRL */ 1968 selected = cache->crls[cache->ncrls - 1]; 1969 1970 /* and populate the cache */ 1971 if (SECSuccess != CachedCrl_Populate(selected)) { 1972 return SECFailure; 1973 } 1974 } 1975 1976 cache->selected = selected; 1977 1978 return SECSuccess; 1979 } 1980 1981 /* initialize a DPCache object */ 1982 static SECStatus 1983 DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer, 1984 const SECItem* subject, SECItem* dp) 1985 { 1986 CRLDPCache* cache = NULL; 1987 PORT_Assert(returned); 1988 /* issuer and dp are allowed to be NULL */ 1989 if (!returned || !subject) { 1990 PORT_Assert(0); 1991 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1992 return SECFailure; 1993 } 1994 *returned = NULL; 1995 cache = PORT_ZAlloc(sizeof(CRLDPCache)); 1996 if (!cache) { 1997 return SECFailure; 1998 } 1999 #ifdef DPC_RWLOCK 2000 cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL); 2001 #else 2002 cache->lock = PR_NewLock(); 2003 #endif 2004 if (!cache->lock) { 2005 PORT_Free(cache); 2006 return SECFailure; 2007 } 2008 if (issuer) { 2009 cache->dbHandle = issuer->dbhandle; 2010 cache->issuerDERCert = SECITEM_DupItem(&issuer->derCert); 2011 } 2012 cache->distributionPoint = SECITEM_DupItem(dp); 2013 cache->subject = SECITEM_DupItem(subject); 2014 cache->lastfetch = 0; 2015 cache->lastcheck = 0; 2016 *returned = cache; 2017 return SECSuccess; 2018 } 2019 2020 /* create an issuer cache object (per CA subject ) */ 2021 static SECStatus 2022 IssuerCache_Create(CRLIssuerCache** returned, CERTCertificate* issuer, 2023 const SECItem* subject, const SECItem* dp) 2024 { 2025 SECStatus rv = SECSuccess; 2026 CRLIssuerCache* cache = NULL; 2027 PORT_Assert(returned); 2028 PORT_Assert(subject); 2029 /* issuer and dp are allowed to be NULL */ 2030 if (!returned || !subject) { 2031 PORT_Assert(0); 2032 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2033 return SECFailure; 2034 } 2035 *returned = NULL; 2036 cache = (CRLIssuerCache*)PORT_ZAlloc(sizeof(CRLIssuerCache)); 2037 if (!cache) { 2038 return SECFailure; 2039 } 2040 cache->subject = SECITEM_DupItem(subject); 2041 #ifdef XCRL 2042 cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL); 2043 if (!cache->lock) { 2044 rv = SECFailure; 2045 } 2046 if (SECSuccess == rv && issuer) { 2047 cache->issuer = CERT_DupCertificate(issuer); 2048 if (!cache->issuer) { 2049 rv = SECFailure; 2050 } 2051 } 2052 #endif 2053 if (SECSuccess != rv) { 2054 PORT_Assert(SECSuccess == IssuerCache_Destroy(cache)); 2055 return SECFailure; 2056 } 2057 *returned = cache; 2058 return SECSuccess; 2059 } 2060 2061 /* add a DPCache to the issuer cache */ 2062 static SECStatus 2063 IssuerCache_AddDP(CRLIssuerCache* cache, CERTCertificate* issuer, 2064 const SECItem* subject, const SECItem* dp, 2065 CRLDPCache** newdpc) 2066 { 2067 /* now create the required DP cache object */ 2068 if (!cache || !subject || !newdpc) { 2069 PORT_Assert(0); 2070 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2071 return SECFailure; 2072 } 2073 if (!dp) { 2074 /* default distribution point */ 2075 SECStatus rv = DPCache_Create(&cache->dpp, issuer, subject, NULL); 2076 if (SECSuccess == rv) { 2077 *newdpc = cache->dpp; 2078 return SECSuccess; 2079 } 2080 } else { 2081 /* we should never hit this until we support multiple DPs */ 2082 PORT_Assert(dp); 2083 /* XCRL allocate a new distribution point cache object, initialize it, 2084 and add it to the hash table of DPs */ 2085 } 2086 return SECFailure; 2087 } 2088 2089 /* add an IssuerCache to the global hash table of issuers */ 2090 static SECStatus 2091 CRLCache_AddIssuer(CRLIssuerCache* issuer) 2092 { 2093 PORT_Assert(issuer); 2094 PORT_Assert(crlcache.issuers); 2095 if (!issuer || !crlcache.issuers) { 2096 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2097 return SECFailure; 2098 } 2099 if (NULL == PL_HashTableAdd(crlcache.issuers, (void*)issuer->subject, 2100 (void*)issuer)) { 2101 return SECFailure; 2102 } 2103 return SECSuccess; 2104 } 2105 2106 /* retrieve the issuer cache object for a given issuer subject */ 2107 static SECStatus 2108 CRLCache_GetIssuerCache(CRLCache* cache, const SECItem* subject, 2109 CRLIssuerCache** returned) 2110 { 2111 /* we need to look up the issuer in the hash table */ 2112 SECStatus rv = SECSuccess; 2113 PORT_Assert(cache); 2114 PORT_Assert(subject); 2115 PORT_Assert(returned); 2116 PORT_Assert(crlcache.issuers); 2117 if (!cache || !subject || !returned || !crlcache.issuers) { 2118 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2119 rv = SECFailure; 2120 } 2121 2122 if (SECSuccess == rv) { 2123 *returned = (CRLIssuerCache*)PL_HashTableLookup(crlcache.issuers, 2124 (void*)subject); 2125 } 2126 2127 return rv; 2128 } 2129 2130 /* retrieve the full CRL object that best matches the content of a DPCache */ 2131 static CERTSignedCrl* 2132 GetBestCRL(CRLDPCache* cache, PRBool entries) 2133 { 2134 CachedCrl* acrl = NULL; 2135 2136 PORT_Assert(cache); 2137 if (!cache) { 2138 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2139 return NULL; 2140 } 2141 2142 if (0 == cache->ncrls) { 2143 /* empty cache*/ 2144 PORT_SetError(SEC_ERROR_CRL_NOT_FOUND); 2145 return NULL; 2146 } 2147 2148 /* if we have a valid full CRL selected, return it */ 2149 if (cache->selected) { 2150 return SEC_DupCrl(cache->selected->crl); 2151 } 2152 2153 /* otherwise, use latest valid DER CRL */ 2154 acrl = cache->crls[cache->ncrls - 1]; 2155 2156 if (acrl && (PR_FALSE == GetOpaqueCRLFields(acrl->crl)->decodingError)) { 2157 SECStatus rv = SECSuccess; 2158 if (PR_TRUE == entries) { 2159 rv = CERT_CompleteCRLDecodeEntries(acrl->crl); 2160 } 2161 if (SECSuccess == rv) { 2162 return SEC_DupCrl(acrl->crl); 2163 } 2164 } 2165 2166 PORT_SetError(SEC_ERROR_CRL_NOT_FOUND); 2167 return NULL; 2168 } 2169 2170 /* get a particular DPCache object from an IssuerCache */ 2171 static CRLDPCache* 2172 IssuerCache_GetDPCache(CRLIssuerCache* cache, const SECItem* dp) 2173 { 2174 CRLDPCache* dpp = NULL; 2175 PORT_Assert(cache); 2176 /* XCRL for now we only support the "default" DP, ie. the 2177 full CRL. So we can return the global one without locking. In 2178 the future we will have a lock */ 2179 PORT_Assert(NULL == dp); 2180 if (!cache || dp) { 2181 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2182 return NULL; 2183 } 2184 #ifdef XCRL 2185 NSSRWLock_LockRead(cache->lock); 2186 #endif 2187 dpp = cache->dpp; 2188 #ifdef XCRL 2189 NSSRWLock_UnlockRead(cache->lock); 2190 #endif 2191 return dpp; 2192 } 2193 2194 /* get a DPCache object for the given issuer subject and dp 2195 Automatically creates the cache object if it doesn't exist yet. 2196 */ 2197 SECStatus 2198 AcquireDPCache(CERTCertificate* issuer, const SECItem* subject, 2199 const SECItem* dp, PRTime t, void* wincx, CRLDPCache** dpcache, 2200 PRBool* writeLocked) 2201 { 2202 SECStatus rv = SECSuccess; 2203 CRLIssuerCache* issuercache = NULL; 2204 #ifdef GLOBAL_RWLOCK 2205 PRBool globalwrite = PR_FALSE; 2206 #endif 2207 PORT_Assert(crlcache.lock); 2208 if (!crlcache.lock) { 2209 /* CRL cache is not initialized */ 2210 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2211 return SECFailure; 2212 } 2213 #ifdef GLOBAL_RWLOCK 2214 NSSRWLock_LockRead(crlcache.lock); 2215 #else 2216 PR_Lock(crlcache.lock); 2217 #endif 2218 rv = CRLCache_GetIssuerCache(&crlcache, subject, &issuercache); 2219 if (SECSuccess != rv) { 2220 #ifdef GLOBAL_RWLOCK 2221 NSSRWLock_UnlockRead(crlcache.lock); 2222 #else 2223 PR_Unlock(crlcache.lock); 2224 #endif 2225 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2226 return SECFailure; 2227 } 2228 if (!issuercache) { 2229 /* there is no cache for this issuer yet. This means this is the 2230 first time we look up a cert from that issuer, and we need to 2231 create the cache. */ 2232 2233 rv = IssuerCache_Create(&issuercache, issuer, subject, dp); 2234 if (SECSuccess == rv && !issuercache) { 2235 PORT_Assert(issuercache); 2236 rv = SECFailure; 2237 } 2238 2239 if (SECSuccess == rv) { 2240 /* This is the first time we look up a cert of this issuer. 2241 Create the DPCache for this DP . */ 2242 rv = IssuerCache_AddDP(issuercache, issuer, subject, dp, dpcache); 2243 } 2244 2245 if (SECSuccess == rv) { 2246 /* lock the DPCache for write to ensure the update happens in this 2247 thread */ 2248 *writeLocked = PR_TRUE; 2249 #ifdef DPC_RWLOCK 2250 NSSRWLock_LockWrite((*dpcache)->lock); 2251 #else 2252 PR_Lock((*dpcache)->lock); 2253 #endif 2254 } 2255 2256 if (SECSuccess == rv) { 2257 /* now add the new issuer cache to the global hash table of 2258 issuers */ 2259 #ifdef GLOBAL_RWLOCK 2260 CRLIssuerCache* existing = NULL; 2261 NSSRWLock_UnlockRead(crlcache.lock); 2262 /* when using a r/w lock for the global cache, check if the issuer 2263 already exists before adding to the hash table */ 2264 NSSRWLock_LockWrite(crlcache.lock); 2265 globalwrite = PR_TRUE; 2266 rv = CRLCache_GetIssuerCache(&crlcache, subject, &existing); 2267 if (!existing) { 2268 #endif 2269 rv = CRLCache_AddIssuer(issuercache); 2270 if (SECSuccess != rv) { 2271 /* failure */ 2272 rv = SECFailure; 2273 } 2274 #ifdef GLOBAL_RWLOCK 2275 } else { 2276 /* somebody else updated before we did */ 2277 IssuerCache_Destroy(issuercache); /* destroy the new object */ 2278 issuercache = existing; /* use the existing one */ 2279 *dpcache = IssuerCache_GetDPCache(issuercache, dp); 2280 } 2281 #endif 2282 } 2283 2284 /* now unlock the global cache. We only want to lock the issuer hash 2285 table addition. Holding it longer would hurt scalability */ 2286 #ifdef GLOBAL_RWLOCK 2287 if (PR_TRUE == globalwrite) { 2288 NSSRWLock_UnlockWrite(crlcache.lock); 2289 globalwrite = PR_FALSE; 2290 } else { 2291 NSSRWLock_UnlockRead(crlcache.lock); 2292 } 2293 #else 2294 PR_Unlock(crlcache.lock); 2295 #endif 2296 2297 /* if there was a failure adding an issuer cache object, destroy it */ 2298 if (SECSuccess != rv && issuercache) { 2299 if (PR_TRUE == *writeLocked) { 2300 #ifdef DPC_RWLOCK 2301 NSSRWLock_UnlockWrite((*dpcache)->lock); 2302 #else 2303 PR_Unlock((*dpcache)->lock); 2304 #endif 2305 } 2306 IssuerCache_Destroy(issuercache); 2307 issuercache = NULL; 2308 } 2309 2310 if (SECSuccess != rv) { 2311 return SECFailure; 2312 } 2313 } else { 2314 #ifdef GLOBAL_RWLOCK 2315 NSSRWLock_UnlockRead(crlcache.lock); 2316 #else 2317 PR_Unlock(crlcache.lock); 2318 #endif 2319 *dpcache = IssuerCache_GetDPCache(issuercache, dp); 2320 } 2321 /* we now have a DPCache that we can use for lookups */ 2322 /* lock it for read, unless we already locked for write */ 2323 if (PR_FALSE == *writeLocked) { 2324 #ifdef DPC_RWLOCK 2325 NSSRWLock_LockRead((*dpcache)->lock); 2326 #else 2327 PR_Lock((*dpcache)->lock); 2328 #endif 2329 } 2330 2331 if (SECSuccess == rv) { 2332 /* currently there is always one and only one DPCache per issuer */ 2333 PORT_Assert(*dpcache); 2334 if (*dpcache) { 2335 /* make sure the DP cache is up to date before using it */ 2336 rv = DPCache_GetUpToDate(*dpcache, issuer, PR_FALSE == *writeLocked, 2337 t, wincx); 2338 } else { 2339 rv = SECFailure; 2340 } 2341 } 2342 return rv; 2343 } 2344 2345 /* unlock access to the DPCache */ 2346 void 2347 ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked) 2348 { 2349 if (!dpcache) { 2350 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2351 return; 2352 } 2353 #ifdef DPC_RWLOCK 2354 if (PR_TRUE == writeLocked) { 2355 NSSRWLock_UnlockWrite(dpcache->lock); 2356 } else { 2357 NSSRWLock_UnlockRead(dpcache->lock); 2358 } 2359 #else 2360 PR_Unlock(dpcache->lock); 2361 #endif 2362 } 2363 2364 SECStatus 2365 cert_CheckCertRevocationStatus(CERTCertificate* cert, CERTCertificate* issuer, 2366 const SECItem* dp, PRTime t, void* wincx, 2367 CERTRevocationStatus* revStatus, 2368 CERTCRLEntryReasonCode* revReason) 2369 { 2370 PRBool lockedwrite = PR_FALSE; 2371 SECStatus rv = SECSuccess; 2372 CRLDPCache* dpcache = NULL; 2373 CERTRevocationStatus status = certRevocationStatusRevoked; 2374 CERTCRLEntryReasonCode reason = crlEntryReasonUnspecified; 2375 CERTCrlEntry* entry = NULL; 2376 dpcacheStatus ds; 2377 2378 if (!cert || !issuer) { 2379 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2380 return SECFailure; 2381 } 2382 2383 if (revStatus) { 2384 *revStatus = status; 2385 } 2386 if (revReason) { 2387 *revReason = reason; 2388 } 2389 2390 if (t && 2391 secCertTimeValid != CERT_CheckCertValidTimes(issuer, t, PR_FALSE)) { 2392 /* we won't be able to check the CRL's signature if the issuer cert 2393 is expired as of the time we are verifying. This may cause a valid 2394 CRL to be cached as bad. short-circuit to avoid this case. */ 2395 PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE); 2396 return SECFailure; 2397 } 2398 2399 rv = AcquireDPCache(issuer, &issuer->derSubject, dp, t, wincx, &dpcache, 2400 &lockedwrite); 2401 PORT_Assert(SECSuccess == rv); 2402 if (SECSuccess != rv) { 2403 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2404 return SECFailure; 2405 } 2406 /* now look up the certificate SN in the DP cache's CRL */ 2407 ds = DPCache_Lookup(dpcache, &cert->serialNumber, &entry); 2408 switch (ds) { 2409 case dpcacheFoundEntry: 2410 PORT_Assert(entry); 2411 /* check the time if we have one */ 2412 if (entry->revocationDate.data && entry->revocationDate.len) { 2413 PRTime revocationDate = 0; 2414 if (SECSuccess == 2415 DER_DecodeTimeChoice(&revocationDate, 2416 &entry->revocationDate)) { 2417 /* we got a good revocation date, only consider the 2418 certificate revoked if the time we are inquiring about 2419 is past the revocation date */ 2420 if (t >= revocationDate) { 2421 rv = SECFailure; 2422 } else { 2423 status = certRevocationStatusValid; 2424 } 2425 } else { 2426 /* invalid revocation date, consider the certificate 2427 permanently revoked */ 2428 rv = SECFailure; 2429 } 2430 } else { 2431 /* no revocation date, certificate is permanently revoked */ 2432 rv = SECFailure; 2433 } 2434 if (SECFailure == rv) { 2435 (void)CERT_FindCRLEntryReasonExten(entry, &reason); 2436 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); 2437 } 2438 break; 2439 2440 case dpcacheEmpty: 2441 /* useful for NIST policy */ 2442 status = certRevocationStatusUnknown; 2443 break; 2444 2445 case dpcacheNoEntry: 2446 status = certRevocationStatusValid; 2447 break; 2448 2449 case dpcacheInvalidCacheError: 2450 /* treat it as unknown and let the caller decide based on 2451 the policy */ 2452 status = certRevocationStatusUnknown; 2453 break; 2454 2455 default: 2456 /* leave status as revoked */ 2457 break; 2458 } 2459 2460 ReleaseDPCache(dpcache, lockedwrite); 2461 if (revStatus) { 2462 *revStatus = status; 2463 } 2464 if (revReason) { 2465 *revReason = reason; 2466 } 2467 return rv; 2468 } 2469 2470 /* check CRL revocation status of given certificate and issuer */ 2471 SECStatus 2472 CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer, const SECItem* dp, 2473 PRTime t, void* wincx) 2474 { 2475 return cert_CheckCertRevocationStatus(cert, issuer, dp, t, wincx, NULL, 2476 NULL); 2477 } 2478 2479 /* retrieve full CRL object that best matches the cache status */ 2480 CERTSignedCrl* 2481 SEC_FindCrlByName(CERTCertDBHandle* handle, SECItem* crlKey, int type) 2482 { 2483 CERTSignedCrl* acrl = NULL; 2484 CRLDPCache* dpcache = NULL; 2485 SECStatus rv = SECSuccess; 2486 PRBool writeLocked = PR_FALSE; 2487 2488 if (!crlKey) { 2489 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2490 return NULL; 2491 } 2492 2493 rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &dpcache, &writeLocked); 2494 if (SECSuccess == rv) { 2495 acrl = GetBestCRL(dpcache, PR_TRUE); /* decode entries, because 2496 SEC_FindCrlByName always returned fully decoded CRLs in the past */ 2497 ReleaseDPCache(dpcache, writeLocked); 2498 } 2499 return acrl; 2500 } 2501 2502 /* invalidate the CRL cache for a given issuer, which forces a refetch of 2503 CRL objects from PKCS#11 tokens */ 2504 void 2505 CERT_CRLCacheRefreshIssuer(CERTCertDBHandle* dbhandle, SECItem* crlKey) 2506 { 2507 CRLDPCache* cache = NULL; 2508 SECStatus rv = SECSuccess; 2509 PRBool writeLocked = PR_FALSE; 2510 PRBool readlocked; 2511 2512 (void)dbhandle; /* silence compiler warnings */ 2513 2514 /* XCRL we will need to refresh all the DPs of the issuer in the future, 2515 not just the default one */ 2516 rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &cache, &writeLocked); 2517 if (SECSuccess != rv) { 2518 return; 2519 } 2520 /* we need to invalidate the DPCache here */ 2521 readlocked = (writeLocked == PR_TRUE ? PR_FALSE : PR_TRUE); 2522 DPCache_LockWrite(); 2523 cache->refresh = PR_TRUE; 2524 DPCache_UnlockWrite(); 2525 ReleaseDPCache(cache, writeLocked); 2526 return; 2527 } 2528 2529 /* add the specified RAM CRL object to the cache */ 2530 SECStatus 2531 CERT_CacheCRL(CERTCertDBHandle* dbhandle, SECItem* newdercrl) 2532 { 2533 CRLDPCache* cache = NULL; 2534 SECStatus rv = SECSuccess; 2535 PRBool writeLocked = PR_FALSE; 2536 PRBool readlocked; 2537 CachedCrl* returned = NULL; 2538 PRBool added = PR_FALSE; 2539 CERTSignedCrl* newcrl = NULL; 2540 int realerror = 0; 2541 2542 if (!dbhandle || !newdercrl) { 2543 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2544 return SECFailure; 2545 } 2546 2547 /* first decode the DER CRL to make sure it's OK */ 2548 newcrl = CERT_DecodeDERCrlWithFlags(NULL, newdercrl, SEC_CRL_TYPE, 2549 CRL_DECODE_DONT_COPY_DER | 2550 CRL_DECODE_SKIP_ENTRIES); 2551 2552 if (!newcrl) { 2553 return SECFailure; 2554 } 2555 2556 /* XXX check if it has IDP extension. If so, do not proceed and set error */ 2557 2558 rv = AcquireDPCache(NULL, &newcrl->crl.derName, NULL, 0, NULL, &cache, 2559 &writeLocked); 2560 if (SECSuccess == rv) { 2561 readlocked = (writeLocked == PR_TRUE ? PR_FALSE : PR_TRUE); 2562 2563 rv = CachedCrl_Create(&returned, newcrl, CRL_OriginExplicit); 2564 if (SECSuccess == rv && returned) { 2565 DPCache_LockWrite(); 2566 rv = DPCache_AddCRL(cache, returned, &added); 2567 if (PR_TRUE != added) { 2568 realerror = PORT_GetError(); 2569 CachedCrl_Destroy(returned); 2570 returned = NULL; 2571 } 2572 DPCache_UnlockWrite(); 2573 } 2574 2575 ReleaseDPCache(cache, writeLocked); 2576 2577 if (!added) { 2578 rv = SECFailure; 2579 } 2580 } 2581 SEC_DestroyCrl(newcrl); /* free the CRL. Either it got added to the cache 2582 and the refcount got bumped, or not, and thus we need to free its 2583 RAM */ 2584 if (realerror) { 2585 PORT_SetError(realerror); 2586 } 2587 return rv; 2588 } 2589 2590 /* remove the specified RAM CRL object from the cache */ 2591 SECStatus 2592 CERT_UncacheCRL(CERTCertDBHandle* dbhandle, SECItem* olddercrl) 2593 { 2594 CRLDPCache* cache = NULL; 2595 SECStatus rv = SECSuccess; 2596 PRBool writeLocked = PR_FALSE; 2597 PRBool readlocked; 2598 PRBool removed = PR_FALSE; 2599 PRUint32 i; 2600 CERTSignedCrl* oldcrl = NULL; 2601 2602 if (!dbhandle || !olddercrl) { 2603 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2604 return SECFailure; 2605 } 2606 2607 /* first decode the DER CRL to make sure it's OK */ 2608 oldcrl = CERT_DecodeDERCrlWithFlags(NULL, olddercrl, SEC_CRL_TYPE, 2609 CRL_DECODE_DONT_COPY_DER | 2610 CRL_DECODE_SKIP_ENTRIES); 2611 2612 if (!oldcrl) { 2613 /* if this DER CRL can't decode, it can't be in the cache */ 2614 return SECFailure; 2615 } 2616 2617 rv = AcquireDPCache(NULL, &oldcrl->crl.derName, NULL, 0, NULL, &cache, 2618 &writeLocked); 2619 if (SECSuccess == rv) { 2620 CachedCrl* returned = NULL; 2621 2622 readlocked = (writeLocked == PR_TRUE ? PR_FALSE : PR_TRUE); 2623 2624 rv = CachedCrl_Create(&returned, oldcrl, CRL_OriginExplicit); 2625 if (SECSuccess == rv && returned) { 2626 DPCache_LockWrite(); 2627 for (i = 0; i < cache->ncrls; i++) { 2628 PRBool dupe = PR_FALSE, updated = PR_FALSE; 2629 rv = CachedCrl_Compare(returned, cache->crls[i], &dupe, 2630 &updated); 2631 if (SECSuccess != rv) { 2632 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2633 break; 2634 } 2635 if (PR_TRUE == dupe) { 2636 rv = DPCache_RemoveCRL(cache, i); /* got a match */ 2637 if (SECSuccess == rv) { 2638 cache->mustchoose = PR_TRUE; 2639 removed = PR_TRUE; 2640 } 2641 break; 2642 } 2643 } 2644 2645 DPCache_UnlockWrite(); 2646 2647 if (SECSuccess != CachedCrl_Destroy(returned)) { 2648 rv = SECFailure; 2649 } 2650 } 2651 2652 ReleaseDPCache(cache, writeLocked); 2653 } 2654 if (SECSuccess != SEC_DestroyCrl(oldcrl)) { 2655 /* need to do this because object is refcounted */ 2656 rv = SECFailure; 2657 } 2658 if (SECSuccess == rv && PR_TRUE != removed) { 2659 PORT_SetError(SEC_ERROR_CRL_NOT_FOUND); 2660 } 2661 return rv; 2662 } 2663 2664 SECStatus 2665 cert_AcquireNamedCRLCache(NamedCRLCache** returned) 2666 { 2667 PORT_Assert(returned); 2668 if (!namedCRLCache.lock) { 2669 PORT_Assert(0); 2670 return SECFailure; 2671 } 2672 PR_Lock(namedCRLCache.lock); 2673 *returned = &namedCRLCache; 2674 return SECSuccess; 2675 } 2676 2677 /* This must be called only while cache is acquired, and the entry is only 2678 * valid until cache is released. 2679 */ 2680 SECStatus 2681 cert_FindCRLByGeneralName(NamedCRLCache* ncc, const SECItem* canonicalizedName, 2682 NamedCRLCacheEntry** retEntry) 2683 { 2684 if (!ncc || !canonicalizedName || !retEntry) { 2685 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2686 return SECFailure; 2687 } 2688 *retEntry = (NamedCRLCacheEntry*)PL_HashTableLookup( 2689 namedCRLCache.entries, (void*)canonicalizedName); 2690 return SECSuccess; 2691 } 2692 2693 SECStatus 2694 cert_ReleaseNamedCRLCache(NamedCRLCache* ncc) 2695 { 2696 if (!ncc) { 2697 return SECFailure; 2698 } 2699 if (!ncc->lock) { 2700 PORT_Assert(0); 2701 return SECFailure; 2702 } 2703 PR_Unlock(namedCRLCache.lock); 2704 return SECSuccess; 2705 } 2706 2707 /* creates new named cache entry from CRL, and tries to add it to CRL cache */ 2708 static SECStatus 2709 addCRLToCache(CERTCertDBHandle* dbhandle, SECItem* crl, 2710 const SECItem* canonicalizedName, NamedCRLCacheEntry** newEntry) 2711 { 2712 SECStatus rv = SECSuccess; 2713 NamedCRLCacheEntry* entry = NULL; 2714 2715 /* create new named entry */ 2716 if (SECSuccess != NamedCRLCacheEntry_Create(newEntry) || !*newEntry) { 2717 /* no need to keep unused CRL around */ 2718 SECITEM_ZfreeItem(crl, PR_TRUE); 2719 return SECFailure; 2720 } 2721 entry = *newEntry; 2722 entry->crl = crl; /* named CRL cache owns DER */ 2723 entry->lastAttemptTime = PR_Now(); 2724 entry->canonicalizedName = SECITEM_DupItem(canonicalizedName); 2725 if (!entry->canonicalizedName) { 2726 rv = NamedCRLCacheEntry_Destroy(entry); /* destroys CRL too */ 2727 PORT_Assert(SECSuccess == rv); 2728 return SECFailure; 2729 } 2730 /* now, attempt to insert CRL into CRL cache */ 2731 if (SECSuccess == CERT_CacheCRL(dbhandle, entry->crl)) { 2732 entry->inCRLCache = PR_TRUE; 2733 entry->successfulInsertionTime = entry->lastAttemptTime; 2734 } else { 2735 switch (PR_GetError()) { 2736 case SEC_ERROR_CRL_ALREADY_EXISTS: 2737 entry->dupe = PR_TRUE; 2738 break; 2739 2740 case SEC_ERROR_BAD_DER: 2741 entry->badDER = PR_TRUE; 2742 break; 2743 2744 /* all other reasons */ 2745 default: 2746 entry->unsupported = PR_TRUE; 2747 break; 2748 } 2749 rv = SECFailure; 2750 /* no need to keep unused CRL around */ 2751 SECITEM_ZfreeItem(entry->crl, PR_TRUE); 2752 entry->crl = NULL; 2753 } 2754 return rv; 2755 } 2756 2757 /* take ownership of CRL, and insert it into the named CRL cache 2758 * and indexed CRL cache 2759 */ 2760 SECStatus 2761 cert_CacheCRLByGeneralName(CERTCertDBHandle* dbhandle, SECItem* crl, 2762 const SECItem* canonicalizedName) 2763 { 2764 NamedCRLCacheEntry *oldEntry, *newEntry = NULL; 2765 NamedCRLCache* ncc = NULL; 2766 SECStatus rv = SECSuccess; 2767 2768 PORT_Assert(namedCRLCache.lock); 2769 PORT_Assert(namedCRLCache.entries); 2770 2771 if (!crl || !canonicalizedName) { 2772 PORT_Assert(0); 2773 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2774 return SECFailure; 2775 } 2776 2777 rv = cert_AcquireNamedCRLCache(&ncc); 2778 PORT_Assert(SECSuccess == rv); 2779 if (SECSuccess != rv) { 2780 SECITEM_ZfreeItem(crl, PR_TRUE); 2781 return SECFailure; 2782 } 2783 rv = cert_FindCRLByGeneralName(ncc, canonicalizedName, &oldEntry); 2784 PORT_Assert(SECSuccess == rv); 2785 if (SECSuccess != rv) { 2786 (void)cert_ReleaseNamedCRLCache(ncc); 2787 SECITEM_ZfreeItem(crl, PR_TRUE); 2788 return SECFailure; 2789 } 2790 if (SECSuccess == 2791 addCRLToCache(dbhandle, crl, canonicalizedName, &newEntry)) { 2792 if (!oldEntry) { 2793 /* add new good entry to the hash table */ 2794 if (NULL == PL_HashTableAdd(namedCRLCache.entries, 2795 (void*)newEntry->canonicalizedName, 2796 (void*)newEntry)) { 2797 PORT_Assert(0); 2798 NamedCRLCacheEntry_Destroy(newEntry); 2799 rv = SECFailure; 2800 } 2801 } else { 2802 PRBool removed; 2803 /* remove the old CRL from the cache if needed */ 2804 if (oldEntry->inCRLCache) { 2805 rv = CERT_UncacheCRL(dbhandle, oldEntry->crl); 2806 PORT_Assert(SECSuccess == rv); 2807 } 2808 removed = PL_HashTableRemove(namedCRLCache.entries, 2809 (void*)oldEntry->canonicalizedName); 2810 PORT_Assert(removed); 2811 if (!removed) { 2812 rv = SECFailure; 2813 /* leak old entry since we couldn't remove it from the hash 2814 * table */ 2815 } else { 2816 PORT_CheckSuccess(NamedCRLCacheEntry_Destroy(oldEntry)); 2817 } 2818 if (NULL == PL_HashTableAdd(namedCRLCache.entries, 2819 (void*)newEntry->canonicalizedName, 2820 (void*)newEntry)) { 2821 PORT_Assert(0); 2822 rv = SECFailure; 2823 } 2824 } 2825 } else { 2826 /* error adding new CRL to cache */ 2827 if (!newEntry) { 2828 // allocation failure in addCRLToCache 2829 rv = SECFailure; 2830 } else if (!oldEntry) { 2831 /* no old cache entry, use the new one even though it's bad */ 2832 if (NULL == PL_HashTableAdd(namedCRLCache.entries, 2833 (void*)newEntry->canonicalizedName, 2834 (void*)newEntry)) { 2835 PORT_Assert(0); 2836 rv = SECFailure; 2837 } 2838 } else { 2839 if (oldEntry->inCRLCache) { 2840 /* previous cache entry was good, keep it and update time */ 2841 oldEntry->lastAttemptTime = newEntry->lastAttemptTime; 2842 /* throw away new bad entry */ 2843 rv = NamedCRLCacheEntry_Destroy(newEntry); 2844 PORT_Assert(SECSuccess == rv); 2845 } else { 2846 /* previous cache entry was bad, just replace it */ 2847 PRBool removed = PL_HashTableRemove( 2848 namedCRLCache.entries, (void*)oldEntry->canonicalizedName); 2849 PORT_Assert(removed); 2850 if (!removed) { 2851 /* leak old entry since we couldn't remove it from the hash 2852 * table */ 2853 rv = SECFailure; 2854 } else { 2855 PORT_CheckSuccess(NamedCRLCacheEntry_Destroy(oldEntry)); 2856 } 2857 if (NULL == PL_HashTableAdd(namedCRLCache.entries, 2858 (void*)newEntry->canonicalizedName, 2859 (void*)newEntry)) { 2860 PORT_Assert(0); 2861 rv = SECFailure; 2862 } 2863 } 2864 } 2865 } 2866 PORT_CheckSuccess(cert_ReleaseNamedCRLCache(ncc)); 2867 2868 return rv; 2869 } 2870 2871 static SECStatus 2872 CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl, CRLOrigin origin) 2873 { 2874 CachedCrl* newcrl = NULL; 2875 if (!returned) { 2876 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2877 return SECFailure; 2878 } 2879 newcrl = PORT_ZAlloc(sizeof(CachedCrl)); 2880 if (!newcrl) { 2881 return SECFailure; 2882 } 2883 newcrl->crl = SEC_DupCrl(crl); 2884 newcrl->origin = origin; 2885 *returned = newcrl; 2886 return SECSuccess; 2887 } 2888 2889 /* empty the cache content */ 2890 static SECStatus 2891 CachedCrl_Depopulate(CachedCrl* crl) 2892 { 2893 if (!crl) { 2894 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2895 return SECFailure; 2896 } 2897 /* destroy the hash table */ 2898 if (crl->entries) { 2899 PL_HashTableDestroy(crl->entries); 2900 crl->entries = NULL; 2901 } 2902 2903 /* free the pre buffer */ 2904 if (crl->prebuffer) { 2905 PreAllocator_Destroy(crl->prebuffer); 2906 crl->prebuffer = NULL; 2907 } 2908 return SECSuccess; 2909 } 2910 2911 static SECStatus 2912 CachedCrl_Destroy(CachedCrl* crl) 2913 { 2914 if (!crl) { 2915 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2916 return SECFailure; 2917 } 2918 CachedCrl_Depopulate(crl); 2919 SEC_DestroyCrl(crl->crl); 2920 PORT_Free(crl); 2921 return SECSuccess; 2922 } 2923 2924 /* create hash table of CRL entries */ 2925 static SECStatus 2926 CachedCrl_Populate(CachedCrl* crlobject) 2927 { 2928 SECStatus rv = SECFailure; 2929 CERTCrlEntry** crlEntry = NULL; 2930 PRUint32 numEntries = 0; 2931 2932 if (!crlobject) { 2933 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2934 return SECFailure; 2935 } 2936 /* complete the entry decoding . XXX thread-safety of CRL object */ 2937 rv = CERT_CompleteCRLDecodeEntries(crlobject->crl); 2938 if (SECSuccess != rv) { 2939 crlobject->unbuildable = PR_TRUE; /* don't try to build this again */ 2940 return SECFailure; 2941 } 2942 2943 if (crlobject->entries && crlobject->prebuffer) { 2944 /* cache is already built */ 2945 return SECSuccess; 2946 } 2947 2948 /* build the hash table from the full CRL */ 2949 /* count CRL entries so we can pre-allocate space for hash table entries */ 2950 for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry; 2951 crlEntry++) { 2952 numEntries++; 2953 } 2954 crlobject->prebuffer = 2955 PreAllocator_Create(numEntries * sizeof(PLHashEntry)); 2956 PORT_Assert(crlobject->prebuffer); 2957 if (!crlobject->prebuffer) { 2958 return SECFailure; 2959 } 2960 /* create a new hash table */ 2961 crlobject->entries = 2962 PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare, PL_CompareValues, 2963 &preAllocOps, crlobject->prebuffer); 2964 PORT_Assert(crlobject->entries); 2965 if (!crlobject->entries) { 2966 return SECFailure; 2967 } 2968 /* add all serial numbers to the hash table */ 2969 for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry; 2970 crlEntry++) { 2971 PL_HashTableAdd(crlobject->entries, &(*crlEntry)->serialNumber, 2972 *crlEntry); 2973 } 2974 2975 return SECSuccess; 2976 } 2977 2978 /* returns true if there are CRLs from PKCS#11 slots */ 2979 static PRBool 2980 DPCache_HasTokenCRLs(CRLDPCache* cache) 2981 { 2982 PRBool answer = PR_FALSE; 2983 PRUint32 i; 2984 for (i = 0; i < cache->ncrls; i++) { 2985 if (cache->crls[i] && (CRL_OriginToken == cache->crls[i]->origin)) { 2986 answer = PR_TRUE; 2987 break; 2988 } 2989 } 2990 return answer; 2991 } 2992 2993 /* are these CRLs the same, as far as the cache is concerned ? */ 2994 /* are these CRLs the same token object but with different DER ? 2995 This can happen if the DER CRL got updated in the token, but the PKCS#11 2996 object ID did not change. NSS softoken has the unfortunate property to 2997 never change the object ID for CRL objects. */ 2998 static SECStatus 2999 CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe, PRBool* isUpdated) 3000 { 3001 PORT_Assert(a); 3002 PORT_Assert(b); 3003 PORT_Assert(isDupe); 3004 PORT_Assert(isUpdated); 3005 if (!a || !b || !isDupe || !isUpdated || !a->crl || !b->crl) { 3006 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 3007 return SECFailure; 3008 } 3009 3010 *isDupe = *isUpdated = PR_FALSE; 3011 3012 if (a == b) { 3013 /* dupe */ 3014 *isDupe = PR_TRUE; 3015 *isUpdated = PR_FALSE; 3016 return SECSuccess; 3017 } 3018 if (b->origin != a->origin) { 3019 /* CRLs of different origins are not considered dupes, 3020 and can't be updated either */ 3021 return SECSuccess; 3022 } 3023 if (CRL_OriginToken == b->origin) { 3024 /* for token CRLs, slot and PKCS#11 object handle must match for CRL 3025 to truly be a dupe */ 3026 if ((b->crl->slot == a->crl->slot) && 3027 (b->crl->pkcs11ID == a->crl->pkcs11ID)) { 3028 /* ASN.1 DER needs to match for dupe check */ 3029 /* could optimize by just checking a few fields like thisUpdate */ 3030 if (SECEqual == 3031 SECITEM_CompareItem(b->crl->derCrl, a->crl->derCrl)) { 3032 *isDupe = PR_TRUE; 3033 } else { 3034 *isUpdated = PR_TRUE; 3035 } 3036 } 3037 return SECSuccess; 3038 } 3039 if (CRL_OriginExplicit == b->origin) { 3040 /* We need to make sure this is the same object that the user provided 3041 to CERT_CacheCRL previously. That API takes a SECItem*, thus, we 3042 just do a pointer comparison here. 3043 */ 3044 if (b->crl->derCrl == a->crl->derCrl) { 3045 *isDupe = PR_TRUE; 3046 } 3047 } 3048 return SECSuccess; 3049 }