security/nss/lib/certdb/crl.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

     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/. */
     5 /*
     6  * Moved from secpkcs7.c
     7  */
     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"
    27 const SEC_ASN1Template SEC_CERTExtensionTemplate[] = {
    28     { SEC_ASN1_SEQUENCE,
    29 	  0, NULL, sizeof(CERTCertExtension) },
    30     { SEC_ASN1_OBJECT_ID,
    31 	  offsetof(CERTCertExtension,id) },
    32     { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN,		/* XXX DER_DEFAULT */
    33 	  offsetof(CERTCertExtension,critical), },
    34     { SEC_ASN1_OCTET_STRING,
    35 	  offsetof(CERTCertExtension,value) },
    36     { 0, }
    37 };
    39 static const SEC_ASN1Template SEC_CERTExtensionsTemplate[] = {
    40     { SEC_ASN1_SEQUENCE_OF, 0,  SEC_CERTExtensionTemplate}
    41 };
    43 /*
    44  * XXX Also, these templates need to be tested; Lisa did the obvious
    45  * translation but they still should be verified.
    46  */
    48 const SEC_ASN1Template CERT_IssuerAndSNTemplate[] = {
    49     { SEC_ASN1_SEQUENCE,
    50 	  0, NULL, sizeof(CERTIssuerAndSN) },
    51     { SEC_ASN1_SAVE,
    52 	  offsetof(CERTIssuerAndSN,derIssuer) },
    53     { SEC_ASN1_INLINE,
    54 	  offsetof(CERTIssuerAndSN,issuer),
    55 	  CERT_NameTemplate },
    56     { SEC_ASN1_INTEGER,
    57 	  offsetof(CERTIssuerAndSN,serialNumber) },
    58     { 0 }
    59 };
    61 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
    62 SEC_ASN1_MKSUB(CERT_TimeChoiceTemplate)
    64 static const SEC_ASN1Template cert_CrlKeyTemplate[] = {
    65     { SEC_ASN1_SEQUENCE,
    66 	  0, NULL, sizeof(CERTCrlKey) },
    67     { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(CERTCrlKey,dummy) },
    68     { SEC_ASN1_SKIP },
    69     { SEC_ASN1_ANY, offsetof(CERTCrlKey,derName) },
    70     { SEC_ASN1_SKIP_REST },
    71     { 0 }
    72 };
    74 static const SEC_ASN1Template cert_CrlEntryTemplate[] = {
    75     { SEC_ASN1_SEQUENCE,
    76 	  0, NULL, sizeof(CERTCrlEntry) },
    77     { SEC_ASN1_INTEGER,
    78 	  offsetof(CERTCrlEntry,serialNumber) },
    79     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
    80 	  offsetof(CERTCrlEntry,revocationDate),
    81           SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
    82     { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
    83 	  offsetof(CERTCrlEntry, extensions),
    84 	  SEC_CERTExtensionTemplate},
    85     { 0 }
    86 };
    88 const SEC_ASN1Template CERT_CrlTemplate[] = {
    89     { SEC_ASN1_SEQUENCE,
    90 	  0, NULL, sizeof(CERTCrl) },
    91     { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof (CERTCrl, version) },
    92     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
    93 	  offsetof(CERTCrl,signatureAlg),
    94 	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate)},
    95     { SEC_ASN1_SAVE,
    96 	  offsetof(CERTCrl,derName) },
    97     { SEC_ASN1_INLINE,
    98 	  offsetof(CERTCrl,name),
    99 	  CERT_NameTemplate },
   100     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
   101 	  offsetof(CERTCrl,lastUpdate),
   102           SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
   103     { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
   104 	  offsetof(CERTCrl,nextUpdate),
   105           SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
   106     { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
   107 	  offsetof(CERTCrl,entries),
   108 	  cert_CrlEntryTemplate },
   109     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
   110 	  SEC_ASN1_EXPLICIT | 0,
   111 	  offsetof(CERTCrl,extensions),
   112 	  SEC_CERTExtensionsTemplate},
   113     { 0 }
   114 };
   116 const SEC_ASN1Template CERT_CrlTemplateNoEntries[] = {
   117     { SEC_ASN1_SEQUENCE,
   118 	  0, NULL, sizeof(CERTCrl) },
   119     { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof (CERTCrl, version) },
   120     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
   121 	  offsetof(CERTCrl,signatureAlg),
   122 	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
   123     { SEC_ASN1_SAVE,
   124 	  offsetof(CERTCrl,derName) },
   125     { SEC_ASN1_INLINE,
   126 	  offsetof(CERTCrl,name),
   127 	  CERT_NameTemplate },
   128     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
   129 	  offsetof(CERTCrl,lastUpdate),
   130           SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
   131     { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
   132 	  offsetof(CERTCrl,nextUpdate),
   133           SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
   134     { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF |
   135       SEC_ASN1_SKIP }, /* skip entries */
   136     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
   137 	  SEC_ASN1_EXPLICIT | 0,
   138 	  offsetof(CERTCrl,extensions),
   139 	  SEC_CERTExtensionsTemplate },
   140     { 0 }
   141 };
   143 const SEC_ASN1Template CERT_CrlTemplateEntriesOnly[] = {
   144     { SEC_ASN1_SEQUENCE,
   145 	  0, NULL, sizeof(CERTCrl) },
   146     { SEC_ASN1_SKIP | SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL },
   147     { SEC_ASN1_SKIP },
   148     { SEC_ASN1_SKIP },
   149     { SEC_ASN1_SKIP | SEC_ASN1_INLINE | SEC_ASN1_XTRN,
   150         offsetof(CERTCrl,lastUpdate),
   151         SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
   152     { SEC_ASN1_SKIP | SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
   153         offsetof(CERTCrl,nextUpdate),
   154         SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
   155     { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
   156 	  offsetof(CERTCrl,entries),
   157 	  cert_CrlEntryTemplate }, /* decode entries */
   158     { SEC_ASN1_SKIP_REST },
   159     { 0 }
   160 };
   162 const SEC_ASN1Template CERT_SignedCrlTemplate[] = {
   163     { SEC_ASN1_SEQUENCE,
   164 	  0, NULL, sizeof(CERTSignedCrl) },
   165     { SEC_ASN1_SAVE,
   166 	  offsetof(CERTSignedCrl,signatureWrap.data) },
   167     { SEC_ASN1_INLINE,
   168 	  offsetof(CERTSignedCrl,crl),
   169 	  CERT_CrlTemplate },
   170     { SEC_ASN1_INLINE | SEC_ASN1_XTRN ,
   171 	  offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
   172 	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
   173     { SEC_ASN1_BIT_STRING,
   174 	  offsetof(CERTSignedCrl,signatureWrap.signature) },
   175     { 0 }
   176 };
   178 static const SEC_ASN1Template cert_SignedCrlTemplateNoEntries[] = {
   179     { SEC_ASN1_SEQUENCE,
   180 	  0, NULL, sizeof(CERTSignedCrl) },
   181     { SEC_ASN1_SAVE,
   182 	  offsetof(CERTSignedCrl,signatureWrap.data) },
   183     { SEC_ASN1_INLINE,
   184 	  offsetof(CERTSignedCrl,crl),
   185 	  CERT_CrlTemplateNoEntries },
   186     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
   187 	  offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
   188 	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
   189     { SEC_ASN1_BIT_STRING,
   190 	  offsetof(CERTSignedCrl,signatureWrap.signature) },
   191     { 0 }
   192 };
   194 const SEC_ASN1Template CERT_SetOfSignedCrlTemplate[] = {
   195     { SEC_ASN1_SET_OF, 0, CERT_SignedCrlTemplate },
   196 };
   198 /* get CRL version */
   199 int cert_get_crl_version(CERTCrl * crl)
   200 {
   201     /* CRL version is defaulted to v1 */
   202     int version = SEC_CRL_VERSION_1;
   203     if (crl && crl->version.data != 0) {
   204 	version = (int)DER_GetUInteger (&crl->version);
   205     }
   206     return version;
   207 }
   210 /* check the entries in the CRL */
   211 SECStatus cert_check_crl_entries (CERTCrl *crl)
   212 {
   213     CERTCrlEntry **entries;
   214     CERTCrlEntry *entry;
   215     PRBool hasCriticalExten = PR_FALSE;
   216     SECStatus rv = SECSuccess;
   218     if (!crl) {
   219         return SECFailure;
   220     }
   222     if (crl->entries == NULL) {
   223         /* CRLs with no entries are valid */
   224         return (SECSuccess);
   225     }
   227     /* Look in the crl entry extensions.  If there is a critical extension,
   228        then the crl version must be v2; otherwise, it should be v1.
   229      */
   230     entries = crl->entries;
   231     while (*entries) {
   232 	entry = *entries;
   233 	if (entry->extensions) {
   234 	    /* If there is a critical extension in the entries, then the
   235 	       CRL must be of version 2.  If we already saw a critical extension,
   236 	       there is no need to check the version again.
   237 	    */
   238             if (hasCriticalExten == PR_FALSE) {
   239                 hasCriticalExten = cert_HasCriticalExtension (entry->extensions);
   240                 if (hasCriticalExten) {
   241                     if (cert_get_crl_version(crl) != SEC_CRL_VERSION_2) { 
   242                         /* only CRL v2 critical extensions are supported */
   243                         PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
   244                         rv = SECFailure;
   245                         break;
   246                     }
   247                 }
   248             }
   250 	    /* For each entry, make sure that it does not contain an unknown
   251 	       critical extension.  If it does, we must reject the CRL since
   252 	       we don't know how to process the extension.
   253 	    */
   254 	    if (cert_HasUnknownCriticalExten (entry->extensions) == PR_TRUE) {
   255 		PORT_SetError (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION);
   256 		rv = SECFailure;
   257 		break;
   258 	    }
   259 	}
   260 	++entries;
   261     }
   262     return(rv);
   263 }
   265 /* Check the version of the CRL.  If there is a critical extension in the crl
   266    or crl entry, then the version must be v2. Otherwise, it should be v1. If
   267    the crl contains critical extension(s), then we must recognized the
   268    extension's OID.
   269    */
   270 SECStatus cert_check_crl_version (CERTCrl *crl)
   271 {
   272     PRBool hasCriticalExten = PR_FALSE;
   273     int version = cert_get_crl_version(crl);
   275     if (version > SEC_CRL_VERSION_2) {
   276 	PORT_SetError (SEC_ERROR_CRL_INVALID_VERSION);
   277 	return (SECFailure);
   278     }
   280     /* Check the crl extensions for a critial extension.  If one is found,
   281        and the version is not v2, then we are done.
   282      */
   283     if (crl->extensions) {
   284 	hasCriticalExten = cert_HasCriticalExtension (crl->extensions);
   285 	if (hasCriticalExten) {
   286             if (version != SEC_CRL_VERSION_2) {
   287                 /* only CRL v2 critical extensions are supported */
   288                 PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
   289                 return (SECFailure);
   290             }
   291 	    /* make sure that there is no unknown critical extension */
   292 	    if (cert_HasUnknownCriticalExten (crl->extensions) == PR_TRUE) {
   293 		PORT_SetError (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION);
   294 		return (SECFailure);
   295 	    }
   296 	}
   297     }
   299     return (SECSuccess);
   300 }
   302 /*
   303  * Generate a database key, based on the issuer name from a
   304  * DER crl.
   305  */
   306 SECStatus
   307 CERT_KeyFromDERCrl(PLArenaPool *arena, SECItem *derCrl, SECItem *key)
   308 {
   309     SECStatus rv;
   310     CERTSignedData sd;
   311     CERTCrlKey crlkey;
   312     PLArenaPool* myArena;
   314     if (!arena) {
   315         /* arena needed for QuickDER */
   316         myArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   317     } else {
   318         myArena = arena;
   319     }
   320     PORT_Memset (&sd, 0, sizeof (sd));
   321     rv = SEC_QuickDERDecodeItem (myArena, &sd, CERT_SignedDataTemplate, derCrl);
   322     if (SECSuccess == rv) {
   323         PORT_Memset (&crlkey, 0, sizeof (crlkey));
   324         rv = SEC_QuickDERDecodeItem(myArena, &crlkey, cert_CrlKeyTemplate, &sd.data);
   325     }
   327     /* make a copy so the data doesn't point to memory inside derCrl, which
   328        may be temporary */
   329     if (SECSuccess == rv) {
   330         rv = SECITEM_CopyItem(arena, key, &crlkey.derName);
   331     }
   333     if (myArena != arena) {
   334         PORT_FreeArena(myArena, PR_FALSE);
   335     }
   337     return rv;
   338 }
   340 #define GetOpaqueCRLFields(x) ((OpaqueCRLFields*)x->opaque)
   342 SECStatus CERT_CompleteCRLDecodeEntries(CERTSignedCrl* crl)
   343 {
   344     SECStatus rv = SECSuccess;
   345     SECItem* crldata = NULL;
   346     OpaqueCRLFields* extended = NULL;
   348     if ( (!crl) ||
   349          (!(extended = (OpaqueCRLFields*) crl->opaque)) ||
   350          (PR_TRUE == extended->decodingError) ) {
   351         rv = SECFailure;
   352     } else {
   353         if (PR_FALSE == extended->partial) {
   354             /* the CRL has already been fully decoded */
   355             return SECSuccess;
   356         }
   357         if (PR_TRUE == extended->badEntries) {
   358             /* the entries decoding already failed */
   359             return SECFailure;
   360         }
   361         crldata = &crl->signatureWrap.data;
   362         if (!crldata) {
   363             rv = SECFailure;
   364         }
   365     }
   367     if (SECSuccess == rv) {
   368         rv = SEC_QuickDERDecodeItem(crl->arena,
   369             &crl->crl,
   370             CERT_CrlTemplateEntriesOnly,
   371             crldata);
   372         if (SECSuccess == rv) {
   373             extended->partial = PR_FALSE; /* successful decode, avoid
   374                 decoding again */
   375         } else {
   376             extended->decodingError = PR_TRUE;
   377             extended->badEntries = PR_TRUE;
   378             /* cache the decoding failure. If it fails the first time,
   379                it will fail again, which will grow the arena and leak
   380                memory, so we want to avoid it */
   381         }
   382         rv = cert_check_crl_entries(&crl->crl);
   383         if (rv != SECSuccess) {
   384             extended->badExtensions = PR_TRUE;
   385         }
   386     }
   387     return rv;
   388 }
   390 /*
   391  * take a DER CRL and decode it into a CRL structure
   392  * allow reusing the input DER without making a copy
   393  */
   394 CERTSignedCrl *
   395 CERT_DecodeDERCrlWithFlags(PLArenaPool *narena, SECItem *derSignedCrl,
   396                           int type, PRInt32 options)
   397 {
   398     PLArenaPool *arena;
   399     CERTSignedCrl *crl;
   400     SECStatus rv;
   401     OpaqueCRLFields* extended = NULL;
   402     const SEC_ASN1Template* crlTemplate = CERT_SignedCrlTemplate;
   403     PRInt32 testOptions = options;
   405     PORT_Assert(derSignedCrl);
   406     if (!derSignedCrl) {
   407         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   408         return NULL;
   409     }
   411     /* Adopting DER requires not copying it.  Code that sets ADOPT flag 
   412      * but doesn't set DONT_COPY probably doesn't know What it is doing.  
   413      * That condition is a programming error in the caller.
   414      */
   415     testOptions &= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);
   416     PORT_Assert(testOptions != CRL_DECODE_ADOPT_HEAP_DER);
   417     if (testOptions == CRL_DECODE_ADOPT_HEAP_DER) {
   418         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   419         return NULL;
   420     }
   422     /* make a new arena if needed */
   423     if (narena == NULL) {
   424     	arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   425 	if ( !arena ) {
   426 	    return NULL;
   427 	}
   428     } else {
   429 	arena = narena;
   430     }
   432     /* allocate the CRL structure */
   433     crl = (CERTSignedCrl *)PORT_ArenaZAlloc(arena, sizeof(CERTSignedCrl));
   434     if ( !crl ) {
   435         PORT_SetError(SEC_ERROR_NO_MEMORY);
   436 	goto loser;
   437     }
   439     crl->arena = arena;
   441     /* allocate opaque fields */
   442     crl->opaque = (void*)PORT_ArenaZAlloc(arena, sizeof(OpaqueCRLFields));
   443     if ( !crl->opaque ) {
   444 	goto loser;
   445     }
   446     extended = (OpaqueCRLFields*) crl->opaque;
   447     if (options & CRL_DECODE_ADOPT_HEAP_DER) {
   448         extended->heapDER = PR_TRUE;
   449     }
   450     if (options & CRL_DECODE_DONT_COPY_DER) {
   451         crl->derCrl = derSignedCrl; /* DER is not copied . The application
   452                                        must keep derSignedCrl until it
   453                                        destroys the CRL */
   454     } else {
   455         crl->derCrl = (SECItem *)PORT_ArenaZAlloc(arena,sizeof(SECItem));
   456         if (crl->derCrl == NULL) {
   457             goto loser;
   458         }
   459         rv = SECITEM_CopyItem(arena, crl->derCrl, derSignedCrl);
   460         if (rv != SECSuccess) {
   461             goto loser;
   462         }
   463     }
   465     /* Save the arena in the inner crl for CRL extensions support */
   466     crl->crl.arena = arena;
   467     if (options & CRL_DECODE_SKIP_ENTRIES) {
   468         crlTemplate = cert_SignedCrlTemplateNoEntries;
   469         extended->partial = PR_TRUE;
   470     }
   472     /* decode the CRL info */
   473     switch (type) {
   474     case SEC_CRL_TYPE:
   475         rv = SEC_QuickDERDecodeItem(arena, crl, crlTemplate, crl->derCrl);
   476         if (rv != SECSuccess) {
   477             extended->badDER = PR_TRUE;
   478             break;
   479         }
   480         /* check for critical extensions */
   481         rv =  cert_check_crl_version (&crl->crl);
   482         if (rv != SECSuccess) {
   483             extended->badExtensions = PR_TRUE;
   484             break;
   485         }
   487         if (PR_TRUE == extended->partial) {
   488             /* partial decoding, don't verify entries */
   489             break;
   490         }
   492         rv = cert_check_crl_entries(&crl->crl);
   493         if (rv != SECSuccess) {
   494             extended->badExtensions = PR_TRUE;
   495         }
   497         break;
   499     default:
   500 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   501 	rv = SECFailure;
   502 	break;
   503     }
   505     if (rv != SECSuccess) {
   506 	goto loser;
   507     }
   509     crl->referenceCount = 1;
   511     return(crl);
   513 loser:
   514     if (options & CRL_DECODE_KEEP_BAD_CRL) {
   515         if (extended) {
   516             extended->decodingError = PR_TRUE;
   517         }
   518         if (crl) {
   519             crl->referenceCount = 1;
   520             return(crl);
   521         }
   522     }
   524     if ((narena == NULL) && arena ) {
   525 	PORT_FreeArena(arena, PR_FALSE);
   526     }
   528     return(0);
   529 }
   531 /*
   532  * take a DER CRL and decode it into a CRL structure
   533  */
   534 CERTSignedCrl *
   535 CERT_DecodeDERCrl(PLArenaPool *narena, SECItem *derSignedCrl, int type)
   536 {
   537     return CERT_DecodeDERCrlWithFlags(narena, derSignedCrl, type,
   538                                       CRL_DECODE_DEFAULT_OPTIONS);
   539 }
   541 /*
   542  * Lookup a CRL in the databases. We mirror the same fast caching data base
   543  *  caching stuff used by certificates....?
   544  * return values :
   545  *
   546  * SECSuccess means we got a valid decodable DER CRL, or no CRL at all.
   547  * Caller may distinguish those cases by the value returned in "decoded".
   548  * When DER CRL is not found, error code will be SEC_ERROR_CRL_NOT_FOUND.
   549  *
   550  * SECFailure means we got a fatal error - most likely, we found a CRL,
   551  * and it failed decoding, or there was an out of memory error. Do NOT ignore
   552  * it and specifically do NOT treat it the same as having no CRL, as this
   553  * can compromise security !!! Ideally, you should treat this case as if you
   554  * received a "catch-all" CRL where all certs you were looking up are
   555  * considered to be revoked
   556  */
   557 static SECStatus
   558 SEC_FindCrlByKeyOnSlot(PK11SlotInfo *slot, SECItem *crlKey, int type,
   559                        CERTSignedCrl** decoded, PRInt32 decodeoptions)
   560 {
   561     SECStatus rv = SECSuccess;
   562     CERTSignedCrl *crl = NULL;
   563     SECItem *derCrl = NULL;
   564     CK_OBJECT_HANDLE crlHandle = 0;
   565     char *url = NULL;
   567     PORT_Assert(decoded);
   568     if (!decoded) {
   569         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   570         return SECFailure;
   571     }
   573     derCrl = PK11_FindCrlByName(&slot, &crlHandle, crlKey, type, &url);
   574     if (derCrl == NULL) {
   575 	/* if we had a problem other than the CRL just didn't exist, return
   576 	 * a failure to the upper level */
   577 	int nsserror = PORT_GetError();
   578 	if (nsserror != SEC_ERROR_CRL_NOT_FOUND) {
   579 	    rv = SECFailure;
   580 	}
   581 	goto loser;
   582     }
   583     PORT_Assert(crlHandle != CK_INVALID_HANDLE);
   584     /* PK11_FindCrlByName obtained a slot reference. */
   586     /* derCRL is a fresh HEAP copy made for us by PK11_FindCrlByName.
   587        Force adoption of the DER CRL from the heap - this will cause it 
   588        to be automatically freed when SEC_DestroyCrl is invoked */
   589     decodeoptions |= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);
   591     crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl, type, decodeoptions);
   592     if (crl) {
   593         crl->slot = slot;
   594         slot = NULL; /* adopt it */
   595 	derCrl = NULL; /* adopted by the crl struct */
   596         crl->pkcs11ID = crlHandle;
   597         if (url) {
   598             crl->url = PORT_ArenaStrdup(crl->arena,url);
   599         }
   600     } else {
   601         rv = SECFailure;
   602     }
   604     if (url) {
   605 	PORT_Free(url);
   606     }
   608     if (slot) {
   609 	PK11_FreeSlot(slot);
   610     }
   612 loser:
   613     if (derCrl) {
   614 	SECITEM_FreeItem(derCrl, PR_TRUE);
   615     }
   617     *decoded = crl;
   619     return rv;
   620 }
   623 CERTSignedCrl *
   624 crl_storeCRL (PK11SlotInfo *slot,char *url,
   625                   CERTSignedCrl *newCrl, SECItem *derCrl, int type)
   626 {
   627     CERTSignedCrl *oldCrl = NULL, *crl = NULL;
   628     PRBool deleteOldCrl = PR_FALSE;
   629     CK_OBJECT_HANDLE crlHandle = CK_INVALID_HANDLE;
   630     SECStatus rv;
   632     PORT_Assert(newCrl);
   633     PORT_Assert(derCrl);
   634     PORT_Assert(type == SEC_CRL_TYPE);
   636     if (type != SEC_CRL_TYPE) {
   637         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   638         return NULL;
   639     }
   641     /* we can't use the cache here because we must look in the same
   642        token */
   643     rv = SEC_FindCrlByKeyOnSlot(slot, &newCrl->crl.derName, type,
   644                                 &oldCrl, CRL_DECODE_SKIP_ENTRIES);
   645     /* if there is an old crl on the token, make sure the one we are
   646        installing is newer. If not, exit out, otherwise delete the
   647        old crl.
   648      */
   649     if (oldCrl != NULL) {
   650 	/* if it's already there, quietly continue */
   651 	if (SECITEM_CompareItem(newCrl->derCrl, oldCrl->derCrl) 
   652 						== SECEqual) {
   653 	    crl = newCrl;
   654 	    crl->slot = PK11_ReferenceSlot(slot);
   655 	    crl->pkcs11ID = oldCrl->pkcs11ID;
   656 	    if (oldCrl->url && !url)
   657 	        url = oldCrl->url;
   658 	    if (url)
   659 		crl->url = PORT_ArenaStrdup(crl->arena, url);
   660 	    goto done;
   661 	}
   662         if (!SEC_CrlIsNewer(&newCrl->crl,&oldCrl->crl)) {
   663             PORT_SetError(SEC_ERROR_OLD_CRL);
   664             goto done;
   665         }
   667         /* if we have a url in the database, use that one */
   668         if (oldCrl->url && !url) {
   669 	    url = oldCrl->url;
   670         }
   672         /* really destroy this crl */
   673         /* first drum it out of the permanment Data base */
   674 	deleteOldCrl = PR_TRUE;
   675     }
   677     /* invalidate CRL cache for this issuer */
   678     CERT_CRLCacheRefreshIssuer(NULL, &newCrl->crl.derName);
   679     /* Write the new entry into the data base */
   680     crlHandle = PK11_PutCrl(slot, derCrl, &newCrl->crl.derName, url, type);
   681     if (crlHandle != CK_INVALID_HANDLE) {
   682 	crl = newCrl;
   683 	crl->slot = PK11_ReferenceSlot(slot);
   684 	crl->pkcs11ID = crlHandle;
   685 	if (url) {
   686 	    crl->url = PORT_ArenaStrdup(crl->arena,url);
   687 	}
   688     }
   690 done:
   691     if (oldCrl) {
   692 	if (deleteOldCrl && crlHandle != CK_INVALID_HANDLE) {
   693 	    SEC_DeletePermCRL(oldCrl);
   694 	}
   695 	SEC_DestroyCrl(oldCrl);
   696     }
   698     return crl;
   699 }
   701 /*
   702  *
   703  * create a new CRL from DER material.
   704  *
   705  * The signature on this CRL must be checked before you
   706  * load it. ???
   707  */
   708 CERTSignedCrl *
   709 SEC_NewCrl(CERTCertDBHandle *handle, char *url, SECItem *derCrl, int type)
   710 {
   711     CERTSignedCrl* retCrl = NULL;
   712     PK11SlotInfo* slot = PK11_GetInternalKeySlot();
   713     retCrl = PK11_ImportCRL(slot, derCrl, url, type, NULL,
   714         CRL_IMPORT_BYPASS_CHECKS, NULL, CRL_DECODE_DEFAULT_OPTIONS);
   715     PK11_FreeSlot(slot);
   717     return retCrl;
   718 }
   720 CERTSignedCrl *
   721 SEC_FindCrlByDERCert(CERTCertDBHandle *handle, SECItem *derCrl, int type)
   722 {
   723     PLArenaPool *arena;
   724     SECItem crlKey;
   725     SECStatus rv;
   726     CERTSignedCrl *crl = NULL;
   728     /* create a scratch arena */
   729     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   730     if ( arena == NULL ) {
   731 	return(NULL);
   732     }
   734     /* extract the database key from the cert */
   735     rv = CERT_KeyFromDERCrl(arena, derCrl, &crlKey);
   736     if ( rv != SECSuccess ) {
   737 	goto loser;
   738     }
   740     /* find the crl */
   741     crl = SEC_FindCrlByName(handle, &crlKey, type);
   743 loser:
   744     PORT_FreeArena(arena, PR_FALSE);
   745     return(crl);
   746 }
   748 CERTSignedCrl* SEC_DupCrl(CERTSignedCrl* acrl)
   749 {
   750     if (acrl)
   751     {
   752         PR_ATOMIC_INCREMENT(&acrl->referenceCount);
   753         return acrl;
   754     }
   755     return NULL;
   756 }
   758 SECStatus
   759 SEC_DestroyCrl(CERTSignedCrl *crl)
   760 {
   761     if (crl) {
   762 	if (PR_ATOMIC_DECREMENT(&crl->referenceCount) < 1) {
   763 	    if (crl->slot) {
   764 		PK11_FreeSlot(crl->slot);
   765 	    }
   766             if (GetOpaqueCRLFields(crl) &&
   767                 PR_TRUE == GetOpaqueCRLFields(crl)->heapDER) {
   768                 SECITEM_FreeItem(crl->derCrl, PR_TRUE);
   769             }
   770             if (crl->arena) {
   771                 PORT_FreeArena(crl->arena, PR_FALSE);
   772             }
   773 	}
   774         return SECSuccess;
   775     } else {
   776         return SECFailure;
   777     }
   778 }
   780 SECStatus
   781 SEC_LookupCrls(CERTCertDBHandle *handle, CERTCrlHeadNode **nodes, int type)
   782 {
   783     CERTCrlHeadNode *head;
   784     PLArenaPool *arena = NULL;
   785     SECStatus rv;
   787     *nodes = NULL;
   789     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   790     if ( arena == NULL ) {
   791 	return SECFailure;
   792     }
   794     /* build a head structure */
   795     head = (CERTCrlHeadNode *)PORT_ArenaAlloc(arena, sizeof(CERTCrlHeadNode));
   796     head->arena = arena;
   797     head->first = NULL;
   798     head->last = NULL;
   799     head->dbhandle = handle;
   801     /* Look up the proper crl types */
   802     *nodes = head;
   804     rv = PK11_LookupCrls(head, type, NULL);
   806     if (rv != SECSuccess) {
   807 	if ( arena ) {
   808 	    PORT_FreeArena(arena, PR_FALSE);
   809 	    *nodes = NULL;
   810 	}
   811     }
   813     return rv;
   814 }
   816 /* These functions simply return the address of the above-declared templates.
   817 ** This is necessary for Windows DLLs.  Sigh.
   818 */
   819 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_IssuerAndSNTemplate)
   820 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CrlTemplate)
   821 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedCrlTemplate)
   822 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SetOfSignedCrlTemplate)
   824 /* CRL cache code starts here */
   826 /* constructor */
   827 static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl,
   828                            CRLOrigin origin);
   829 /* destructor */
   830 static SECStatus CachedCrl_Destroy(CachedCrl* crl);
   832 /* create hash table of CRL entries */
   833 static SECStatus CachedCrl_Populate(CachedCrl* crlobject);
   835 /* empty the cache content */
   836 static SECStatus CachedCrl_Depopulate(CachedCrl* crl);
   838 /* are these CRLs the same, as far as the cache is concerned ?
   839    Or are they the same token object, but with different DER ? */
   841 static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe,
   842                                 PRBool* isUpdated);
   844 /* create a DPCache object */
   845 static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
   846                          const SECItem* subject, SECItem* dp);
   848 /* destructor for CRL DPCache object */
   849 static SECStatus DPCache_Destroy(CRLDPCache* cache);
   851 /* add a new CRL object to the dynamic array of CRLs of the DPCache, and
   852    returns the cached CRL object . Needs write access to DPCache. */
   853 static SECStatus DPCache_AddCRL(CRLDPCache* cache, CachedCrl* crl,
   854                                 PRBool* added);
   856 /* fetch the CRL for this DP from the PKCS#11 tokens */
   857 static SECStatus DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate,
   858                                          void* wincx);
   860 /* update the content of the CRL cache, including fetching of CRLs, and
   861    reprocessing with specified issuer and date */
   862 static SECStatus DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate* issuer,
   863                          PRBool readlocked, PRTime vfdate, void* wincx);
   865 /* returns true if there are CRLs from PKCS#11 slots */
   866 static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache);
   868 /* remove CRL at offset specified */
   869 static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset);
   871 /* Pick best CRL to use . needs write access */
   872 static SECStatus DPCache_SelectCRL(CRLDPCache* cache);
   874 /* create an issuer cache object (per CA subject ) */
   875 static SECStatus IssuerCache_Create(CRLIssuerCache** returned,
   876                              CERTCertificate* issuer,
   877                              const SECItem* subject, const SECItem* dp);
   879 /* destructor for CRL IssuerCache object */
   880 SECStatus IssuerCache_Destroy(CRLIssuerCache* cache);
   882 /* add a DPCache to the issuer cache */
   883 static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache,
   884                                    CERTCertificate* issuer,
   885                                    const SECItem* subject,
   886                                    const SECItem* dp, CRLDPCache** newdpc);
   888 /* get a particular DPCache object from an IssuerCache */
   889 static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache,
   890                                           const SECItem* dp);
   892 /*
   893 ** Pre-allocator hash allocator ops.
   894 */
   896 /* allocate memory for hash table */
   897 static void * PR_CALLBACK
   898 PreAllocTable(void *pool, PRSize size)
   899 {
   900     PreAllocator* alloc = (PreAllocator*)pool;
   901     PORT_Assert(alloc);
   902     if (!alloc)
   903     {
   904         /* no allocator, or buffer full */
   905         return NULL;
   906     }
   907     if (size > (alloc->len - alloc->used))
   908     {
   909         /* initial buffer full, let's use the arena */
   910         alloc->extra += size;
   911         return PORT_ArenaAlloc(alloc->arena, size);
   912     }
   913     /* use the initial buffer */
   914     alloc->used += size;
   915     return (char*) alloc->data + alloc->used - size;
   916 }
   918 /* free hash table memory.
   919    Individual PreAllocator elements cannot be freed, so this is a no-op. */
   920 static void PR_CALLBACK
   921 PreFreeTable(void *pool, void *item)
   922 {
   923 }
   925 /* allocate memory for hash table */
   926 static PLHashEntry * PR_CALLBACK
   927 PreAllocEntry(void *pool, const void *key)
   928 {
   929     return PreAllocTable(pool, sizeof(PLHashEntry));
   930 }
   932 /* free hash table entry.
   933    Individual PreAllocator elements cannot be freed, so this is a no-op. */
   934 static void PR_CALLBACK
   935 PreFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
   936 {
   937 }
   939 /* methods required for PL hash table functions */
   940 static PLHashAllocOps preAllocOps =
   941 {
   942     PreAllocTable, PreFreeTable,
   943     PreAllocEntry, PreFreeEntry
   944 };
   946 /* destructor for PreAllocator object */
   947 void PreAllocator_Destroy(PreAllocator* PreAllocator)
   948 {
   949     if (!PreAllocator)
   950     {
   951         return;
   952     }
   953     if (PreAllocator->arena)
   954     {
   955         PORT_FreeArena(PreAllocator->arena, PR_TRUE);
   956     }
   957 }
   959 /* constructor for PreAllocator object */
   960 PreAllocator* PreAllocator_Create(PRSize size)
   961 {
   962     PLArenaPool* arena = NULL;
   963     PreAllocator* prebuffer = NULL;
   964     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   965     if (!arena)
   966     {
   967         return NULL;
   968     }
   969     prebuffer = (PreAllocator*)PORT_ArenaZAlloc(arena,
   970                                                 sizeof(PreAllocator));
   971     if (!prebuffer)
   972     {
   973         PORT_FreeArena(arena, PR_TRUE);
   974         return NULL;
   975     }
   976     prebuffer->arena = arena;
   978     if (size)
   979     {
   980         prebuffer->len = size;
   981         prebuffer->data = PORT_ArenaAlloc(arena, size);
   982         if (!prebuffer->data)
   983         {
   984             PORT_FreeArena(arena, PR_TRUE);
   985             return NULL;
   986         }
   987     }
   988     return prebuffer;
   989 }
   991 /* global Named CRL cache object */
   992 static NamedCRLCache namedCRLCache = { NULL, NULL };
   994 /* global CRL cache object */
   995 static CRLCache crlcache = { NULL, NULL };
   997 /* initial state is off */
   998 static PRBool crlcache_initialized = PR_FALSE;
  1000 PRTime CRLCache_Empty_TokenFetch_Interval = 60 * 1000000; /* how often
  1001     to query the tokens for CRL objects, in order to discover new objects, if
  1002     the cache does not contain any token CRLs . In microseconds */
  1004 PRTime CRLCache_TokenRefetch_Interval = 600 * 1000000 ; /* how often
  1005     to query the tokens for CRL objects, in order to discover new objects, if
  1006     the cache already contains token CRLs In microseconds */
  1008 PRTime CRLCache_ExistenceCheck_Interval = 60 * 1000000; /* how often to check
  1009     if a token CRL object still exists. In microseconds */
  1011 /* this function is called at NSS initialization time */
  1012 SECStatus InitCRLCache(void)
  1014     if (PR_FALSE == crlcache_initialized)
  1016         PORT_Assert(NULL == crlcache.lock);
  1017         PORT_Assert(NULL == crlcache.issuers);
  1018         PORT_Assert(NULL == namedCRLCache.lock);
  1019         PORT_Assert(NULL == namedCRLCache.entries);
  1020         if (crlcache.lock || crlcache.issuers || namedCRLCache.lock ||
  1021             namedCRLCache.entries)
  1023             /* CRL cache already partially initialized */
  1024             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1025             return SECFailure;
  1027 #ifdef GLOBAL_RWLOCK
  1028         crlcache.lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
  1029 #else
  1030         crlcache.lock = PR_NewLock();
  1031 #endif
  1032         namedCRLCache.lock = PR_NewLock();
  1033         crlcache.issuers = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
  1034                                   PL_CompareValues, NULL, NULL);
  1035         namedCRLCache.entries = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
  1036                                   PL_CompareValues, NULL, NULL);
  1037         if (!crlcache.lock || !namedCRLCache.lock || !crlcache.issuers ||
  1038             !namedCRLCache.entries)
  1040             if (crlcache.lock)
  1042 #ifdef GLOBAL_RWLOCK
  1043                 NSSRWLock_Destroy(crlcache.lock);
  1044 #else
  1045                 PR_DestroyLock(crlcache.lock);
  1046 #endif
  1047                 crlcache.lock = NULL;
  1049             if (namedCRLCache.lock)
  1051                 PR_DestroyLock(namedCRLCache.lock);
  1052                 namedCRLCache.lock = NULL;
  1054             if (crlcache.issuers)
  1056                 PL_HashTableDestroy(crlcache.issuers);
  1057                 crlcache.issuers = NULL;
  1059             if (namedCRLCache.entries)
  1061                 PL_HashTableDestroy(namedCRLCache.entries);
  1062                 namedCRLCache.entries = NULL;
  1065             return SECFailure;
  1067         crlcache_initialized = PR_TRUE;
  1068         return SECSuccess;
  1070     else
  1072         PORT_Assert(crlcache.lock);
  1073         PORT_Assert(crlcache.issuers);
  1074         if ( (NULL == crlcache.lock) || (NULL == crlcache.issuers) )
  1076             /* CRL cache not fully initialized */
  1077             return SECFailure;
  1079         else
  1081             /* CRL cache already initialized */
  1082             return SECSuccess;
  1087 /* destructor for CRL DPCache object */
  1088 static SECStatus DPCache_Destroy(CRLDPCache* cache)
  1090     PRUint32 i = 0;
  1091     PORT_Assert(cache);
  1092     if (!cache)
  1094         PORT_Assert(0);
  1095         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1096         return SECFailure;
  1098     if (cache->lock)
  1100 #ifdef DPC_RWLOCK
  1101         NSSRWLock_Destroy(cache->lock);
  1102 #else
  1103         PR_DestroyLock(cache->lock);
  1104 #endif
  1106     else
  1108         PORT_Assert(0);
  1109         return SECFailure;
  1111     /* destroy all our CRL objects */
  1112     for (i=0;i<cache->ncrls;i++)
  1114         if (!cache->crls || !cache->crls[i] ||
  1115             SECSuccess != CachedCrl_Destroy(cache->crls[i]))
  1117             return SECFailure;
  1120     /* free the array of CRLs */
  1121     if (cache->crls)
  1123 	PORT_Free(cache->crls);
  1125     /* destroy the cert */
  1126     if (cache->issuer)
  1128         CERT_DestroyCertificate(cache->issuer);
  1130     /* free the subject */
  1131     if (cache->subject)
  1133         SECITEM_FreeItem(cache->subject, PR_TRUE);
  1135     /* free the distribution points */
  1136     if (cache->distributionPoint)
  1138         SECITEM_FreeItem(cache->distributionPoint, PR_TRUE);
  1140     PORT_Free(cache);
  1141     return SECSuccess;
  1144 /* destructor for CRL IssuerCache object */
  1145 SECStatus IssuerCache_Destroy(CRLIssuerCache* cache)
  1147     PORT_Assert(cache);
  1148     if (!cache)
  1150         PORT_Assert(0);
  1151         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1152         return SECFailure;
  1154 #ifdef XCRL
  1155     if (cache->lock)
  1157         NSSRWLock_Destroy(cache->lock);
  1159     else
  1161         PORT_Assert(0);
  1162         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1163         return SECFailure;
  1165     if (cache->issuer)
  1167         CERT_DestroyCertificate(cache->issuer);
  1169 #endif
  1170     /* free the subject */
  1171     if (cache->subject)
  1173         SECITEM_FreeItem(cache->subject, PR_TRUE);
  1175     if (SECSuccess != DPCache_Destroy(cache->dpp))
  1177         PORT_Assert(0);
  1178         return SECFailure;
  1180     PORT_Free(cache);
  1181     return SECSuccess;
  1184 /* create a named CRL entry object */
  1185 static SECStatus NamedCRLCacheEntry_Create(NamedCRLCacheEntry** returned)
  1187     NamedCRLCacheEntry* entry = NULL;
  1188     if (!returned)
  1190         PORT_Assert(0);
  1191         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1192         return SECFailure;
  1194     *returned = NULL;
  1195     entry = (NamedCRLCacheEntry*) PORT_ZAlloc(sizeof(NamedCRLCacheEntry));
  1196     if (!entry)
  1198         return SECFailure;
  1200     *returned = entry;
  1201     return SECSuccess;
  1204 /* destroy a named CRL entry object */
  1205 static SECStatus NamedCRLCacheEntry_Destroy(NamedCRLCacheEntry* entry)
  1207     if (!entry)
  1209         PORT_Assert(0);
  1210         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1211         return SECFailure;
  1213     if (entry->crl)
  1215         /* named CRL cache owns DER memory */
  1216         SECITEM_ZfreeItem(entry->crl, PR_TRUE);
  1218     if (entry->canonicalizedName)
  1220         SECITEM_FreeItem(entry->canonicalizedName, PR_TRUE);
  1222     PORT_Free(entry);
  1223     return SECSuccess;
  1226 /* callback function used in hash table destructor */
  1227 static PRIntn PR_CALLBACK FreeIssuer(PLHashEntry *he, PRIntn i, void *arg)
  1229     CRLIssuerCache* issuer = NULL;
  1230     SECStatus* rv = (SECStatus*) arg;
  1232     PORT_Assert(he);
  1233     if (!he)
  1235         return HT_ENUMERATE_NEXT;
  1237     issuer = (CRLIssuerCache*) he->value;
  1238     PORT_Assert(issuer);
  1239     if (issuer)
  1241         if (SECSuccess != IssuerCache_Destroy(issuer))
  1243             PORT_Assert(rv);
  1244             if (rv)
  1246                 *rv = SECFailure;
  1248             return HT_ENUMERATE_NEXT;
  1251     return HT_ENUMERATE_NEXT;
  1254 /* callback function used in hash table destructor */
  1255 static PRIntn PR_CALLBACK FreeNamedEntries(PLHashEntry *he, PRIntn i, void *arg)
  1257     NamedCRLCacheEntry* entry = NULL;
  1258     SECStatus* rv = (SECStatus*) arg;
  1260     PORT_Assert(he);
  1261     if (!he)
  1263         return HT_ENUMERATE_NEXT;
  1265     entry = (NamedCRLCacheEntry*) he->value;
  1266     PORT_Assert(entry);
  1267     if (entry)
  1269         if (SECSuccess != NamedCRLCacheEntry_Destroy(entry))
  1271             PORT_Assert(rv);
  1272             if (rv)
  1274                 *rv = SECFailure;
  1276             return HT_ENUMERATE_NEXT;
  1279     return HT_ENUMERATE_NEXT;
  1282 /* needs to be called at NSS shutdown time
  1283    This will destroy the global CRL cache, including 
  1284    - the hash table of issuer cache objects
  1285    - the issuer cache objects
  1286    - DPCache objects in issuer cache objects */
  1287 SECStatus ShutdownCRLCache(void)
  1289     SECStatus rv = SECSuccess;
  1290     if (PR_FALSE == crlcache_initialized &&
  1291         !crlcache.lock && !crlcache.issuers)
  1293         /* CRL cache has already been shut down */
  1294         return SECSuccess;
  1296     if (PR_TRUE == crlcache_initialized &&
  1297         (!crlcache.lock || !crlcache.issuers || !namedCRLCache.lock ||
  1298          !namedCRLCache.entries))
  1300         /* CRL cache has partially been shut down */
  1301         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1302         return SECFailure;
  1304     /* empty the CRL cache */
  1305     /* free the issuers */
  1306     PL_HashTableEnumerateEntries(crlcache.issuers, &FreeIssuer, &rv);
  1307     /* free the hash table of issuers */
  1308     PL_HashTableDestroy(crlcache.issuers);
  1309     crlcache.issuers = NULL;
  1310     /* free the global lock */
  1311 #ifdef GLOBAL_RWLOCK
  1312     NSSRWLock_Destroy(crlcache.lock);
  1313 #else
  1314     PR_DestroyLock(crlcache.lock);
  1315 #endif
  1316     crlcache.lock = NULL;
  1318     /* empty the named CRL cache. This must be done after freeing the CRL
  1319      * cache, since some CRLs in this cache are in the memory for the other  */
  1320     /* free the entries */
  1321     PL_HashTableEnumerateEntries(namedCRLCache.entries, &FreeNamedEntries, &rv);
  1322     /* free the hash table of issuers */
  1323     PL_HashTableDestroy(namedCRLCache.entries);
  1324     namedCRLCache.entries = NULL;
  1325     /* free the global lock */
  1326     PR_DestroyLock(namedCRLCache.lock);
  1327     namedCRLCache.lock = NULL;
  1329     crlcache_initialized = PR_FALSE;
  1330     return rv;
  1333 /* add a new CRL object to the dynamic array of CRLs of the DPCache, and
  1334    returns the cached CRL object . Needs write access to DPCache. */
  1335 static SECStatus DPCache_AddCRL(CRLDPCache* cache, CachedCrl* newcrl,
  1336                                 PRBool* added)
  1338     CachedCrl** newcrls = NULL;
  1339     PRUint32 i = 0;
  1340     PORT_Assert(cache);
  1341     PORT_Assert(newcrl);
  1342     PORT_Assert(added);
  1343     if (!cache || !newcrl || !added)
  1345         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1346         return SECFailure;
  1349     *added = PR_FALSE;
  1350     /* before adding a new CRL, check if it is a duplicate */
  1351     for (i=0;i<cache->ncrls;i++)
  1353         CachedCrl* existing = NULL;
  1354         SECStatus rv = SECSuccess;
  1355         PRBool dupe = PR_FALSE, updated = PR_FALSE;
  1356         if (!cache->crls)
  1358             PORT_Assert(0);
  1359             return SECFailure;
  1361         existing = cache->crls[i];
  1362         if (!existing)
  1364             PORT_Assert(0);
  1365             return SECFailure;
  1367         rv = CachedCrl_Compare(existing, newcrl, &dupe, &updated);
  1368         if (SECSuccess != rv)
  1370             PORT_Assert(0);
  1371             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1372             return SECFailure;
  1374         if (PR_TRUE == dupe)
  1376             /* dupe */
  1377             PORT_SetError(SEC_ERROR_CRL_ALREADY_EXISTS);
  1378             return SECSuccess;
  1380         if (PR_TRUE == updated)
  1382             /* this token CRL is in the same slot and has the same object ID,
  1383                but different content. We need to remove the old object */
  1384             if (SECSuccess != DPCache_RemoveCRL(cache, i))
  1386                 PORT_Assert(0);
  1387                 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1388                 return PR_FALSE;
  1393     newcrls = (CachedCrl**)PORT_Realloc(cache->crls,
  1394         (cache->ncrls+1)*sizeof(CachedCrl*));
  1395     if (!newcrls)
  1397         return SECFailure;
  1399     cache->crls = newcrls;
  1400     cache->ncrls++;
  1401     cache->crls[cache->ncrls-1] = newcrl;
  1402     *added = PR_TRUE;
  1403     return SECSuccess;
  1406 /* remove CRL at offset specified */
  1407 static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset)
  1409     CachedCrl* acrl = NULL;
  1410     PORT_Assert(cache);
  1411     if (!cache || (!cache->crls) || (!(offset<cache->ncrls)) )
  1413         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1414         return SECFailure;
  1416     acrl = cache->crls[offset];
  1417     PORT_Assert(acrl);
  1418     if (!acrl)
  1420         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1421         return SECFailure;
  1423     cache->crls[offset] = cache->crls[cache->ncrls-1];
  1424     cache->crls[cache->ncrls-1] = NULL;
  1425     cache->ncrls--;
  1426     if (cache->selected == acrl) {
  1427         cache->selected = NULL;
  1429     if (SECSuccess != CachedCrl_Destroy(acrl))
  1431         PORT_Assert(0);
  1432         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1433         return SECFailure;
  1435     return SECSuccess;
  1438 /* check whether a CRL object stored in a PKCS#11 token still exists in
  1439    that token . This has to be efficient (the entire CRL value cannot be
  1440    transferred accross the token boundaries), so this is accomplished by
  1441    simply fetching the subject attribute and making sure it hasn't changed .
  1442    Note that technically, the CRL object could have been replaced with a new
  1443    PKCS#11 object of the same ID and subject (which actually happens in
  1444    softoken), but this function has no way of knowing that the object
  1445    value changed, since CKA_VALUE isn't checked. */
  1446 static PRBool TokenCRLStillExists(CERTSignedCrl* crl)
  1448     NSSItem newsubject;
  1449     SECItem subject;
  1450     CK_ULONG crl_class;
  1451     PRStatus status;
  1452     PK11SlotInfo* slot = NULL;
  1453     nssCryptokiObject instance;
  1454     NSSArena* arena;
  1455     PRBool xstatus = PR_TRUE;
  1456     SECItem* oldSubject = NULL;
  1458     PORT_Assert(crl);
  1459     if (!crl)
  1461         return PR_FALSE;
  1463     slot = crl->slot;
  1464     PORT_Assert(crl->slot);
  1465     if (!slot)
  1467         return PR_FALSE;
  1469     oldSubject = &crl->crl.derName;
  1470     PORT_Assert(oldSubject);
  1471     if (!oldSubject)
  1473         return PR_FALSE;
  1476     /* query subject and type attributes in order to determine if the
  1477        object has been deleted */
  1479     /* first, make an nssCryptokiObject */
  1480     instance.handle = crl->pkcs11ID;
  1481     PORT_Assert(instance.handle);
  1482     if (!instance.handle)
  1484         return PR_FALSE;
  1486     instance.token = PK11Slot_GetNSSToken(slot);
  1487     PORT_Assert(instance.token);
  1488     if (!instance.token)
  1490         return PR_FALSE;
  1492     instance.isTokenObject = PR_TRUE;
  1493     instance.label = NULL;
  1495     arena = NSSArena_Create();
  1496     PORT_Assert(arena);
  1497     if (!arena)
  1499         return PR_FALSE;
  1502     status = nssCryptokiCRL_GetAttributes(&instance,
  1503                                           NULL,  /* XXX sessionOpt */
  1504                                           arena,
  1505                                           NULL,
  1506                                           &newsubject,  /* subject */
  1507                                           &crl_class,   /* class */
  1508                                           NULL,
  1509                                           NULL);
  1510     if (PR_SUCCESS == status)
  1512         subject.data = newsubject.data;
  1513         subject.len = newsubject.size;
  1514         if (SECITEM_CompareItem(oldSubject, &subject) != SECEqual)
  1516             xstatus = PR_FALSE;
  1518         if (CKO_NETSCAPE_CRL != crl_class)
  1520             xstatus = PR_FALSE;
  1523     else
  1525         xstatus = PR_FALSE;
  1527     NSSArena_Destroy(arena);
  1528     return xstatus;
  1531 /* verify the signature of a CRL against its issuer at a given date */
  1532 static SECStatus CERT_VerifyCRL(
  1533     CERTSignedCrl* crlobject,
  1534     CERTCertificate* issuer,
  1535     PRTime vfdate,
  1536     void* wincx)
  1538     return CERT_VerifySignedData(&crlobject->signatureWrap,
  1539                                  issuer, vfdate, wincx);
  1542 /* verify a CRL and update cache state */
  1543 static SECStatus CachedCrl_Verify(CRLDPCache* cache, CachedCrl* crlobject,
  1544                           PRTime vfdate, void* wincx)
  1546     /*  Check if it is an invalid CRL
  1547         if we got a bad CRL, we want to cache it in order to avoid
  1548         subsequent fetches of this same identical bad CRL. We set
  1549         the cache to the invalid state to ensure that all certs on this
  1550         DP are considered to have unknown status from now on. The cache
  1551         object will remain in this state until the bad CRL object
  1552         is removed from the token it was fetched from. If the cause
  1553         of the failure is that we didn't have the issuer cert to
  1554         verify the signature, this state can be cleared when
  1555         the issuer certificate becomes available if that causes the
  1556         signature to verify */
  1558     if (!cache || !crlobject)
  1560         PORT_Assert(0);
  1561         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1562         return SECFailure;
  1564     if (PR_TRUE == GetOpaqueCRLFields(crlobject->crl)->decodingError)
  1566         crlobject->sigChecked = PR_TRUE; /* we can never verify a CRL
  1567             with bogus DER. Mark it checked so we won't try again */
  1568         PORT_SetError(SEC_ERROR_BAD_DER);
  1569         return SECSuccess;
  1571     else
  1573         SECStatus signstatus = SECFailure;
  1574         if (cache->issuer)
  1576             signstatus = CERT_VerifyCRL(crlobject->crl, cache->issuer, vfdate,
  1577                                         wincx);
  1579         if (SECSuccess != signstatus)
  1581             if (!cache->issuer)
  1583                 /* we tried to verify without an issuer cert . This is
  1584                    because this CRL came through a call to SEC_FindCrlByName.
  1585                    So, we don't cache this verification failure. We'll try
  1586                    to verify the CRL again when a certificate from that issuer
  1587                    becomes available */
  1588             } else
  1590                 crlobject->sigChecked = PR_TRUE;
  1592             PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
  1593             return SECSuccess;
  1594         } else
  1596             crlobject->sigChecked = PR_TRUE;
  1597             crlobject->sigValid = PR_TRUE;
  1601     return SECSuccess;
  1604 /* fetch the CRLs for this DP from the PKCS#11 tokens */
  1605 static SECStatus DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate,
  1606                                          void* wincx)
  1608     SECStatus rv = SECSuccess;
  1609     CERTCrlHeadNode head;
  1610     if (!cache)
  1612         PORT_Assert(0);
  1613         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1614         return SECFailure;
  1616     /* first, initialize list */
  1617     memset(&head, 0, sizeof(head));
  1618     head.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1619     rv = pk11_RetrieveCrls(&head, cache->subject, wincx);
  1621     /* if this function fails, something very wrong happened, such as an out
  1622        of memory error during CRL decoding. We don't want to proceed and must
  1623        mark the cache object invalid */
  1624     if (SECFailure == rv)
  1626         /* fetch failed, add error bit */
  1627         cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
  1628     } else
  1630         /* fetch was successful, clear this error bit */
  1631         cache->invalid &= (~CRL_CACHE_LAST_FETCH_FAILED);
  1634     /* add any CRLs found to our array */
  1635     if (SECSuccess == rv)
  1637         CERTCrlNode* crlNode = NULL;
  1639         for (crlNode = head.first; crlNode ; crlNode = crlNode->next)
  1641             CachedCrl* returned = NULL;
  1642             CERTSignedCrl* crlobject = crlNode->crl;
  1643             if (!crlobject)
  1645                 PORT_Assert(0);
  1646                 continue;
  1648             rv = CachedCrl_Create(&returned, crlobject, CRL_OriginToken);
  1649             if (SECSuccess == rv)
  1651                 PRBool added = PR_FALSE;
  1652                 rv = DPCache_AddCRL(cache, returned, &added);
  1653                 if (PR_TRUE != added)
  1655                     rv = CachedCrl_Destroy(returned);
  1656                     returned = NULL;
  1658                 else if (vfdate)
  1660                     rv = CachedCrl_Verify(cache, returned, vfdate, wincx);
  1663             else
  1665                 /* not enough memory to add the CRL to the cache. mark it
  1666                    invalid so we will try again . */
  1667                 cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
  1669             if (SECFailure == rv)
  1671                 break;
  1676     if (head.arena)
  1678         CERTCrlNode* crlNode = NULL;
  1679         /* clean up the CRL list in case we got a partial one
  1680            during a failed fetch */
  1681         for (crlNode = head.first; crlNode ; crlNode = crlNode->next)
  1683             if (crlNode->crl)
  1685                 SEC_DestroyCrl(crlNode->crl); /* free the CRL. Either it got
  1686                    added to the cache and the refcount got bumped, or not, and
  1687                    thus we need to free its RAM */
  1690         PORT_FreeArena(head.arena, PR_FALSE); /* destroy CRL list */
  1693     return rv;
  1696 static SECStatus CachedCrl_GetEntry(CachedCrl* crl, const SECItem* sn,
  1697                                     CERTCrlEntry** returned)
  1699     CERTCrlEntry* acrlEntry;
  1701     PORT_Assert(crl);
  1702     PORT_Assert(crl->entries);
  1703     PORT_Assert(sn);
  1704     PORT_Assert(returned);
  1705     if (!crl || !sn || !returned || !crl->entries)
  1707         PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1708         return SECFailure;
  1710     acrlEntry = PL_HashTableLookup(crl->entries, (void*)sn);
  1711     if (acrlEntry)
  1713         *returned = acrlEntry;
  1715     else
  1717         *returned = NULL;
  1719     return SECSuccess;
  1722 /* check if a particular SN is in the CRL cache and return its entry */
  1723 dpcacheStatus DPCache_Lookup(CRLDPCache* cache, const SECItem* sn,
  1724                          CERTCrlEntry** returned)
  1726     SECStatus rv;
  1727     if (!cache || !sn || !returned)
  1729         PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1730         /* no cache or SN to look up, or no way to return entry */
  1731         return dpcacheCallerError;
  1733     *returned = NULL;
  1734     if (0 != cache->invalid)
  1736         /* the cache contains a bad CRL, or there was a CRL fetching error. */
  1737         PORT_SetError(SEC_ERROR_CRL_INVALID);
  1738         return dpcacheInvalidCacheError;
  1740     if (!cache->selected)
  1742         /* no CRL means no entry to return. This is OK, except for
  1743          * NIST policy */
  1744         return dpcacheEmpty;
  1746     rv = CachedCrl_GetEntry(cache->selected, sn, returned);
  1747     if (SECSuccess != rv)
  1749         return dpcacheLookupError;
  1751     else
  1753         if (*returned)
  1755             return dpcacheFoundEntry;
  1757         else
  1759             return dpcacheNoEntry;
  1764 #if defined(DPC_RWLOCK)
  1766 #define DPCache_LockWrite() \
  1767 { \
  1768     if (readlocked) \
  1769     { \
  1770         NSSRWLock_UnlockRead(cache->lock); \
  1771     } \
  1772     NSSRWLock_LockWrite(cache->lock); \
  1775 #define DPCache_UnlockWrite() \
  1776 { \
  1777     if (readlocked) \
  1778     { \
  1779         NSSRWLock_LockRead(cache->lock); \
  1780     } \
  1781     NSSRWLock_UnlockWrite(cache->lock); \
  1784 #else
  1786 /* with a global lock, we are always locked for read before we need write
  1787    access, so do nothing */
  1789 #define DPCache_LockWrite() \
  1790 { \
  1793 #define DPCache_UnlockWrite() \
  1794 { \
  1797 #endif
  1799 /* update the content of the CRL cache, including fetching of CRLs, and
  1800    reprocessing with specified issuer and date . We are always holding
  1801    either the read or write lock on DPCache upon entry. */
  1802 static SECStatus DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate*
  1803                                      issuer, PRBool readlocked, PRTime vfdate,
  1804                                      void* wincx)
  1806     /* Update the CRLDPCache now. We don't cache token CRL lookup misses
  1807        yet, as we have no way of getting notified of new PKCS#11 object
  1808        creation that happens in a token  */
  1809     SECStatus rv = SECSuccess;
  1810     PRUint32 i = 0;
  1811     PRBool forcedrefresh = PR_FALSE;
  1812     PRBool dirty = PR_FALSE; /* whether something was changed in the
  1813                                 cache state during this update cycle */
  1814     PRBool hastokenCRLs = PR_FALSE;
  1815     PRTime now = 0;
  1816     PRTime lastfetch = 0;
  1817     PRBool mustunlock = PR_FALSE;
  1819     if (!cache)
  1821         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1822         return SECFailure;
  1825     /* first, make sure we have obtained all the CRLs we need.
  1826        We do an expensive token fetch in the following cases :
  1827        1) cache is empty because no fetch was ever performed yet
  1828        2) cache is explicitly set to refresh state
  1829        3) cache is in invalid state because last fetch failed
  1830        4) cache contains no token CRLs, and it's been more than one minute
  1831           since the last fetch
  1832        5) cache contains token CRLs, and it's been more than 10 minutes since
  1833           the last fetch
  1834     */
  1835     forcedrefresh = cache->refresh;
  1836     lastfetch = cache->lastfetch;
  1837     if (PR_TRUE != forcedrefresh && 
  1838         (!(cache->invalid & CRL_CACHE_LAST_FETCH_FAILED)))
  1840         now = PR_Now();
  1841         hastokenCRLs = DPCache_HasTokenCRLs(cache);
  1843     if ( (0 == lastfetch) ||
  1845          (PR_TRUE == forcedrefresh) ||
  1847          (cache->invalid & CRL_CACHE_LAST_FETCH_FAILED) ||
  1849          ( (PR_FALSE == hastokenCRLs) &&
  1850            ( (now - cache->lastfetch > CRLCache_Empty_TokenFetch_Interval) ||
  1851              (now < cache->lastfetch)) ) ||
  1853          ( (PR_TRUE == hastokenCRLs) &&
  1854            ((now - cache->lastfetch > CRLCache_TokenRefetch_Interval) ||
  1855             (now < cache->lastfetch)) ) )
  1857         /* the cache needs to be refreshed, and/or we had zero CRL for this
  1858            DP. Try to get one from PKCS#11 tokens */
  1859         DPCache_LockWrite();
  1860         /* check if another thread updated before us, and skip update if so */
  1861         if (lastfetch == cache->lastfetch)
  1863             /* we are the first */
  1864             rv = DPCache_FetchFromTokens(cache, vfdate, wincx);
  1865             if (PR_TRUE == cache->refresh)
  1867                 cache->refresh = PR_FALSE; /* clear refresh state */
  1869             dirty = PR_TRUE;
  1870             cache->lastfetch = PR_Now();
  1872         DPCache_UnlockWrite();
  1875     /* now, make sure we have no extraneous CRLs (deleted token objects)
  1876        we'll do this inexpensive existence check either
  1877        1) if there was a token object fetch
  1878        2) every minute */
  1879     if (( PR_TRUE != dirty) && (!now) )
  1881         now = PR_Now();
  1883     if ( (PR_TRUE == dirty) ||
  1884          ( (now - cache->lastcheck > CRLCache_ExistenceCheck_Interval) ||
  1885            (now < cache->lastcheck)) )
  1887         PRTime lastcheck = cache->lastcheck;
  1888         mustunlock = PR_FALSE;
  1889         /* check if all CRLs still exist */
  1890         for (i = 0; (i < cache->ncrls) ; i++)
  1892             CachedCrl* savcrl = cache->crls[i];
  1893             if ( (!savcrl) || (savcrl && CRL_OriginToken != savcrl->origin))
  1895                 /* we only want to check token CRLs */
  1896                 continue;
  1898             if ((PR_TRUE != TokenCRLStillExists(savcrl->crl)))
  1901                 /* this CRL is gone */
  1902                 if (PR_TRUE != mustunlock)
  1904                     DPCache_LockWrite();
  1905                     mustunlock = PR_TRUE;
  1907                 /* first, we need to check if another thread did an update
  1908                    before we did */
  1909                 if (lastcheck == cache->lastcheck)
  1911                     /* the CRL is gone. And we are the one to do the update */
  1912                     DPCache_RemoveCRL(cache, i);
  1913                     dirty = PR_TRUE;
  1915                 /* stay locked here intentionally so we do all the other
  1916                    updates in this thread for the remaining CRLs */
  1919         if (PR_TRUE == mustunlock)
  1921             cache->lastcheck = PR_Now();
  1922             DPCache_UnlockWrite();
  1923             mustunlock = PR_FALSE;
  1927     /* add issuer certificate if it was previously unavailable */
  1928     if (issuer && (NULL == cache->issuer) &&
  1929         (SECSuccess == CERT_CheckCertUsage(issuer, KU_CRL_SIGN)))
  1931         /* if we didn't have a valid issuer cert yet, but we do now. add it */
  1932         DPCache_LockWrite();
  1933         if (!cache->issuer)
  1935             dirty = PR_TRUE;
  1936             cache->issuer = CERT_DupCertificate(issuer);    
  1938         DPCache_UnlockWrite();
  1941     /* verify CRLs that couldn't be checked when inserted into the cache
  1942        because the issuer cert or a verification date was unavailable.
  1943        These are CRLs that were inserted into the cache through
  1944        SEC_FindCrlByName, or through manual insertion, rather than through a
  1945        certificate verification (CERT_CheckCRL) */
  1947     if (cache->issuer && vfdate )
  1949 	mustunlock = PR_FALSE;
  1950         /* re-process all unverified CRLs */
  1951         for (i = 0; i < cache->ncrls ; i++)
  1953             CachedCrl* savcrl = cache->crls[i];
  1954             if (!savcrl)
  1956                 continue;
  1958             if (PR_TRUE != savcrl->sigChecked)
  1960                 if (!mustunlock)
  1962                     DPCache_LockWrite();
  1963                     mustunlock = PR_TRUE;
  1965                 /* first, we need to check if another thread updated
  1966                    it before we did, and abort if it has been modified since
  1967                    we acquired the lock. Make sure first that the CRL is still
  1968                    in the array at the same position */
  1969                 if ( (i<cache->ncrls) && (savcrl == cache->crls[i]) &&
  1970                      (PR_TRUE != savcrl->sigChecked) )
  1972                     /* the CRL is still there, unverified. Do it */
  1973                     CachedCrl_Verify(cache, savcrl, vfdate, wincx);
  1974                     dirty = PR_TRUE;
  1976                 /* stay locked here intentionally so we do all the other
  1977                    updates in this thread for the remaining CRLs */
  1979             if (mustunlock && !dirty)
  1981                 DPCache_UnlockWrite();
  1982                 mustunlock = PR_FALSE;
  1987     if (dirty || cache->mustchoose)
  1989         /* changes to the content of the CRL cache necessitate examining all
  1990            CRLs for selection of the most appropriate one to cache */
  1991 	if (!mustunlock)
  1993 	    DPCache_LockWrite();
  1994 	    mustunlock = PR_TRUE;
  1996         DPCache_SelectCRL(cache);
  1997         cache->mustchoose = PR_FALSE;
  1999     if (mustunlock)
  2000 	DPCache_UnlockWrite();
  2002     return rv;
  2005 /* callback for qsort to sort by thisUpdate */
  2006 static int SortCRLsByThisUpdate(const void* arg1, const void* arg2)
  2008     PRTime timea, timeb;
  2009     SECStatus rv = SECSuccess;
  2010     CachedCrl* a, *b;
  2012     a = *(CachedCrl**) arg1;
  2013     b = *(CachedCrl**) arg2;
  2015     if (!a || !b)
  2017         PORT_Assert(0);
  2018         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2019         rv = SECFailure;
  2022     if (SECSuccess == rv)
  2024         rv = DER_DecodeTimeChoice(&timea, &a->crl->crl.lastUpdate);
  2026     if (SECSuccess == rv)
  2028         rv = DER_DecodeTimeChoice(&timeb, &b->crl->crl.lastUpdate);
  2030     if (SECSuccess == rv)
  2032         if (timea > timeb)
  2034             return 1; /* a is better than b */
  2036         if (timea < timeb )
  2038             return -1; /* a is not as good as b */
  2042     /* if they are equal, or if all else fails, use pointer differences */
  2043     PORT_Assert(a != b); /* they should never be equal */
  2044     return a>b?1:-1;
  2047 /* callback for qsort to sort a set of disparate CRLs, some of which are
  2048    invalid DER or failed signature check.
  2050    Validated CRLs are differentiated by thisUpdate .
  2051    Validated CRLs are preferred over non-validated CRLs .
  2052    Proper DER CRLs are preferred over non-DER data .
  2053 */
  2054 static int SortImperfectCRLs(const void* arg1, const void* arg2)
  2056     CachedCrl* a, *b;
  2058     a = *(CachedCrl**) arg1;
  2059     b = *(CachedCrl**) arg2;
  2061     if (!a || !b)
  2063         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2064         PORT_Assert(0);
  2066     else
  2068         PRBool aDecoded = PR_FALSE, bDecoded = PR_FALSE;
  2069         if ( (PR_TRUE == a->sigValid) && (PR_TRUE == b->sigValid) )
  2071             /* both CRLs have been validated, choose the latest one */
  2072             return SortCRLsByThisUpdate(arg1, arg2);
  2074         if (PR_TRUE == a->sigValid)
  2076             return 1; /* a is greater than b */
  2078         if (PR_TRUE == b->sigValid)
  2080             return -1; /* a is not as good as b */
  2082         aDecoded = GetOpaqueCRLFields(a->crl)->decodingError;
  2083         bDecoded = GetOpaqueCRLFields(b->crl)->decodingError;
  2084         /* neither CRL had its signature check pass */
  2085         if ( (PR_FALSE == aDecoded) && (PR_FALSE == bDecoded) )
  2087             /* both CRLs are proper DER, choose the latest one */
  2088             return SortCRLsByThisUpdate(arg1, arg2);
  2090         if (PR_FALSE == aDecoded)
  2092             return 1; /* a is better than b */
  2094         if (PR_FALSE == bDecoded)
  2096             return -1; /* a is not as good as b */
  2098         /* both are invalid DER. sigh. */
  2100     /* if they are equal, or if all else fails, use pointer differences */
  2101     PORT_Assert(a != b); /* they should never be equal */
  2102     return a>b?1:-1;
  2106 /* Pick best CRL to use . needs write access */
  2107 static SECStatus DPCache_SelectCRL(CRLDPCache* cache)
  2109     PRUint32 i;
  2110     PRBool valid = PR_TRUE;
  2111     CachedCrl* selected = NULL;
  2113     PORT_Assert(cache);
  2114     if (!cache)
  2116         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2117         return SECFailure;
  2119     /* if any invalid CRL is present, then the CRL cache is
  2120        considered invalid, for security reasons */
  2121     for (i = 0 ; i<cache->ncrls; i++)
  2123         if (!cache->crls[i] || !cache->crls[i]->sigChecked ||
  2124             !cache->crls[i]->sigValid)
  2126             valid = PR_FALSE;
  2127             break;
  2130     if (PR_TRUE == valid)
  2132         /* all CRLs are valid, clear this error */
  2133         cache->invalid &= (~CRL_CACHE_INVALID_CRLS);
  2134     } else
  2136         /* some CRLs are invalid, set this error */
  2137         cache->invalid |= CRL_CACHE_INVALID_CRLS;
  2140     if (cache->invalid)
  2142         /* cache is in an invalid state, so reset it */
  2143         if (cache->selected)
  2145             cache->selected = NULL;
  2147         /* also sort the CRLs imperfectly */
  2148         qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*),
  2149               SortImperfectCRLs);
  2150         return SECSuccess;
  2152     /* all CRLs are good, sort them by thisUpdate */
  2153     qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*),
  2154           SortCRLsByThisUpdate);
  2156     if (cache->ncrls)
  2158         /* pick the newest CRL */
  2159         selected = cache->crls[cache->ncrls-1];
  2161         /* and populate the cache */
  2162         if (SECSuccess != CachedCrl_Populate(selected))
  2164             return SECFailure;
  2168     cache->selected = selected;
  2170     return SECSuccess;
  2173 /* initialize a DPCache object */
  2174 static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
  2175                          const SECItem* subject, SECItem* dp)
  2177     CRLDPCache* cache = NULL;
  2178     PORT_Assert(returned);
  2179     /* issuer and dp are allowed to be NULL */
  2180     if (!returned || !subject)
  2182         PORT_Assert(0);
  2183         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2184         return SECFailure;
  2186     *returned = NULL;
  2187     cache = PORT_ZAlloc(sizeof(CRLDPCache));
  2188     if (!cache)
  2190         return SECFailure;
  2192 #ifdef DPC_RWLOCK
  2193     cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
  2194 #else
  2195     cache->lock = PR_NewLock();
  2196 #endif
  2197     if (!cache->lock)
  2199 	PORT_Free(cache);
  2200         return SECFailure;
  2202     if (issuer)
  2204         cache->issuer = CERT_DupCertificate(issuer);
  2206     cache->distributionPoint = SECITEM_DupItem(dp);
  2207     cache->subject = SECITEM_DupItem(subject);
  2208     cache->lastfetch = 0;
  2209     cache->lastcheck = 0;
  2210     *returned = cache;
  2211     return SECSuccess;
  2214 /* create an issuer cache object (per CA subject ) */
  2215 static SECStatus IssuerCache_Create(CRLIssuerCache** returned,
  2216                              CERTCertificate* issuer,
  2217                              const SECItem* subject, const SECItem* dp)
  2219     SECStatus rv = SECSuccess;
  2220     CRLIssuerCache* cache = NULL;
  2221     PORT_Assert(returned);
  2222     PORT_Assert(subject);
  2223     /* issuer and dp are allowed to be NULL */
  2224     if (!returned || !subject)
  2226         PORT_Assert(0);
  2227         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2228         return SECFailure;
  2230     *returned = NULL;
  2231     cache = (CRLIssuerCache*) PORT_ZAlloc(sizeof(CRLIssuerCache));
  2232     if (!cache)
  2234         return SECFailure;
  2236     cache->subject = SECITEM_DupItem(subject);
  2237 #ifdef XCRL
  2238     cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
  2239     if (!cache->lock)
  2241         rv = SECFailure;
  2243     if (SECSuccess == rv && issuer)
  2245         cache->issuer = CERT_DupCertificate(issuer);
  2246         if (!cache->issuer)
  2248             rv = SECFailure;
  2251 #endif
  2252     if (SECSuccess != rv)
  2254         PORT_Assert(SECSuccess == IssuerCache_Destroy(cache));
  2255         return SECFailure;
  2257     *returned = cache;
  2258     return SECSuccess;
  2261 /* add a DPCache to the issuer cache */
  2262 static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache,
  2263                                    CERTCertificate* issuer,
  2264                                    const SECItem* subject,
  2265                                    const SECItem* dp,
  2266                                    CRLDPCache** newdpc)
  2268     /* now create the required DP cache object */
  2269     if (!cache || !subject || !newdpc)
  2271         PORT_Assert(0);
  2272         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2273         return SECFailure;
  2275     if (!dp)
  2277         /* default distribution point */
  2278         SECStatus rv = DPCache_Create(&cache->dpp, issuer, subject, NULL);
  2279         if (SECSuccess == rv)
  2281             *newdpc = cache->dpp;
  2282             return SECSuccess;
  2285     else
  2287         /* we should never hit this until we support multiple DPs */
  2288         PORT_Assert(dp);
  2289         /* XCRL allocate a new distribution point cache object, initialize it,
  2290            and add it to the hash table of DPs */
  2292     return SECFailure;
  2295 /* add an IssuerCache to the global hash table of issuers */
  2296 static SECStatus CRLCache_AddIssuer(CRLIssuerCache* issuer)
  2298     PORT_Assert(issuer);
  2299     PORT_Assert(crlcache.issuers);
  2300     if (!issuer || !crlcache.issuers)
  2302         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2303         return SECFailure;
  2305     if (NULL == PL_HashTableAdd(crlcache.issuers, (void*) issuer->subject,
  2306                                 (void*) issuer))
  2308         return SECFailure;
  2310     return SECSuccess;
  2313 /* retrieve the issuer cache object for a given issuer subject */
  2314 static SECStatus CRLCache_GetIssuerCache(CRLCache* cache,
  2315                                          const SECItem* subject,
  2316                                          CRLIssuerCache** returned)
  2318     /* we need to look up the issuer in the hash table */
  2319     SECStatus rv = SECSuccess;
  2320     PORT_Assert(cache);
  2321     PORT_Assert(subject);
  2322     PORT_Assert(returned);
  2323     PORT_Assert(crlcache.issuers);
  2324     if (!cache || !subject || !returned || !crlcache.issuers)
  2326         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2327         rv = SECFailure;
  2330     if (SECSuccess == rv)
  2332         *returned = (CRLIssuerCache*) PL_HashTableLookup(crlcache.issuers,
  2333                                                          (void*) subject);
  2336     return rv;
  2339 /* retrieve the full CRL object that best matches the content of a DPCache */
  2340 static CERTSignedCrl* GetBestCRL(CRLDPCache* cache, PRBool entries)
  2342     CachedCrl* acrl = NULL;
  2344     PORT_Assert(cache);
  2345     if (!cache)
  2347         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2348         return NULL;
  2351     if (0 == cache->ncrls)
  2353         /* empty cache*/
  2354         PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
  2355         return NULL;
  2358     /* if we have a valid full CRL selected, return it */
  2359     if (cache->selected)
  2361         return SEC_DupCrl(cache->selected->crl);
  2364     /* otherwise, use latest valid DER CRL */
  2365     acrl = cache->crls[cache->ncrls-1];
  2367     if (acrl && (PR_FALSE == GetOpaqueCRLFields(acrl->crl)->decodingError) )
  2369         SECStatus rv = SECSuccess;
  2370         if (PR_TRUE == entries)
  2372             rv = CERT_CompleteCRLDecodeEntries(acrl->crl);
  2374         if (SECSuccess == rv)
  2376             return SEC_DupCrl(acrl->crl);
  2380     PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
  2381     return NULL;
  2384 /* get a particular DPCache object from an IssuerCache */
  2385 static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache, const SECItem* dp)
  2387     CRLDPCache* dpp = NULL;
  2388     PORT_Assert(cache);
  2389     /* XCRL for now we only support the "default" DP, ie. the
  2390        full CRL. So we can return the global one without locking. In
  2391        the future we will have a lock */
  2392     PORT_Assert(NULL == dp);
  2393     if (!cache || dp)
  2395         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2396         return NULL;
  2398 #ifdef XCRL
  2399     NSSRWLock_LockRead(cache->lock);
  2400 #endif
  2401     dpp = cache->dpp;
  2402 #ifdef XCRL
  2403     NSSRWLock_UnlockRead(cache->lock);
  2404 #endif
  2405     return dpp;
  2408 /* get a DPCache object for the given issuer subject and dp
  2409    Automatically creates the cache object if it doesn't exist yet.
  2410    */
  2411 SECStatus AcquireDPCache(CERTCertificate* issuer, const SECItem* subject,
  2412                          const SECItem* dp, PRTime t, void* wincx,
  2413                          CRLDPCache** dpcache, PRBool* writeLocked)
  2415     SECStatus rv = SECSuccess;
  2416     CRLIssuerCache* issuercache = NULL;
  2417 #ifdef GLOBAL_RWLOCK
  2418     PRBool globalwrite = PR_FALSE;
  2419 #endif
  2420     PORT_Assert(crlcache.lock);
  2421     if (!crlcache.lock)
  2423         /* CRL cache is not initialized */
  2424         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2425         return SECFailure;
  2427 #ifdef GLOBAL_RWLOCK
  2428     NSSRWLock_LockRead(crlcache.lock);
  2429 #else
  2430     PR_Lock(crlcache.lock);
  2431 #endif
  2432     rv = CRLCache_GetIssuerCache(&crlcache, subject, &issuercache);
  2433     if (SECSuccess != rv)
  2435 #ifdef GLOBAL_RWLOCK
  2436         NSSRWLock_UnlockRead(crlcache.lock);
  2437 #else
  2438         PR_Unlock(crlcache.lock);
  2439 #endif
  2440         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2441         return SECFailure;
  2443     if (!issuercache)
  2445         /* there is no cache for this issuer yet. This means this is the
  2446            first time we look up a cert from that issuer, and we need to
  2447            create the cache. */
  2449         rv = IssuerCache_Create(&issuercache, issuer, subject, dp);
  2450         if (SECSuccess == rv && !issuercache)
  2452             PORT_Assert(issuercache);
  2453             rv = SECFailure;
  2456         if (SECSuccess == rv)
  2458             /* This is the first time we look up a cert of this issuer.
  2459                Create the DPCache for this DP . */
  2460             rv = IssuerCache_AddDP(issuercache, issuer, subject, dp, dpcache);
  2463         if (SECSuccess == rv)
  2465             /* lock the DPCache for write to ensure the update happens in this
  2466                thread */
  2467             *writeLocked = PR_TRUE;
  2468 #ifdef DPC_RWLOCK
  2469             NSSRWLock_LockWrite((*dpcache)->lock);
  2470 #else
  2471             PR_Lock((*dpcache)->lock);
  2472 #endif
  2475         if (SECSuccess == rv)
  2477             /* now add the new issuer cache to the global hash table of
  2478                issuers */
  2479 #ifdef GLOBAL_RWLOCK
  2480             CRLIssuerCache* existing = NULL;
  2481             NSSRWLock_UnlockRead(crlcache.lock);
  2482             /* when using a r/w lock for the global cache, check if the issuer
  2483                already exists before adding to the hash table */
  2484             NSSRWLock_LockWrite(crlcache.lock);
  2485             globalwrite = PR_TRUE;
  2486             rv = CRLCache_GetIssuerCache(&crlcache, subject, &existing);
  2487             if (!existing)
  2489 #endif
  2490                 rv = CRLCache_AddIssuer(issuercache);
  2491                 if (SECSuccess != rv)
  2493                     /* failure */
  2494                     rv = SECFailure;
  2496 #ifdef GLOBAL_RWLOCK
  2498             else
  2500                 /* somebody else updated before we did */
  2501                 IssuerCache_Destroy(issuercache); /* destroy the new object */
  2502                 issuercache = existing; /* use the existing one */
  2503                 *dpcache = IssuerCache_GetDPCache(issuercache, dp);
  2505 #endif
  2508         /* now unlock the global cache. We only want to lock the issuer hash
  2509            table addition. Holding it longer would hurt scalability */
  2510 #ifdef GLOBAL_RWLOCK
  2511         if (PR_TRUE == globalwrite)
  2513             NSSRWLock_UnlockWrite(crlcache.lock);
  2514             globalwrite = PR_FALSE;
  2516         else
  2518             NSSRWLock_UnlockRead(crlcache.lock);
  2520 #else
  2521         PR_Unlock(crlcache.lock);
  2522 #endif
  2524         /* if there was a failure adding an issuer cache object, destroy it */
  2525         if (SECSuccess != rv && issuercache)
  2527             if (PR_TRUE == *writeLocked)
  2529 #ifdef DPC_RWLOCK
  2530                 NSSRWLock_UnlockWrite((*dpcache)->lock);
  2531 #else
  2532                 PR_Unlock((*dpcache)->lock);
  2533 #endif
  2535             IssuerCache_Destroy(issuercache);
  2536             issuercache = NULL;
  2539         if (SECSuccess != rv)
  2541             return SECFailure;
  2543     } else
  2545 #ifdef GLOBAL_RWLOCK
  2546         NSSRWLock_UnlockRead(crlcache.lock);
  2547 #else
  2548         PR_Unlock(crlcache.lock);
  2549 #endif
  2550         *dpcache = IssuerCache_GetDPCache(issuercache, dp);
  2552     /* we now have a DPCache that we can use for lookups */
  2553     /* lock it for read, unless we already locked for write */
  2554     if (PR_FALSE == *writeLocked)
  2556 #ifdef DPC_RWLOCK
  2557         NSSRWLock_LockRead((*dpcache)->lock);
  2558 #else
  2559         PR_Lock((*dpcache)->lock);
  2560 #endif
  2563     if (SECSuccess == rv)
  2565         /* currently there is always one and only one DPCache per issuer */
  2566         PORT_Assert(*dpcache);
  2567         if (*dpcache)
  2569             /* make sure the DP cache is up to date before using it */
  2570             rv = DPCache_GetUpToDate(*dpcache, issuer, PR_FALSE == *writeLocked,
  2571                                      t, wincx);
  2573         else
  2575             rv = SECFailure;
  2578     return rv;
  2581 /* unlock access to the DPCache */
  2582 void ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked)
  2584     if (!dpcache)
  2586         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2587         return;
  2589 #ifdef DPC_RWLOCK
  2590     if (PR_TRUE == writeLocked)
  2592         NSSRWLock_UnlockWrite(dpcache->lock);
  2594     else
  2596         NSSRWLock_UnlockRead(dpcache->lock);
  2598 #else
  2599     PR_Unlock(dpcache->lock);
  2600 #endif
  2603 SECStatus
  2604 cert_CheckCertRevocationStatus(CERTCertificate* cert, CERTCertificate* issuer,
  2605                                const SECItem* dp, PRTime t, void *wincx,
  2606                                CERTRevocationStatus *revStatus,
  2607                                CERTCRLEntryReasonCode *revReason)
  2609     PRBool lockedwrite = PR_FALSE;
  2610     SECStatus rv = SECSuccess;
  2611     CRLDPCache* dpcache = NULL;
  2612     CERTRevocationStatus status = certRevocationStatusRevoked;
  2613     CERTCRLEntryReasonCode reason = crlEntryReasonUnspecified;
  2614     CERTCrlEntry* entry = NULL;
  2615     dpcacheStatus ds;
  2617     if (!cert || !issuer)
  2619         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2620         return SECFailure;
  2623     if (revStatus)
  2625         *revStatus = status;
  2627     if (revReason)
  2629         *revReason = reason;
  2632     if (t && secCertTimeValid != CERT_CheckCertValidTimes(issuer, t, PR_FALSE))
  2634         /* we won't be able to check the CRL's signature if the issuer cert
  2635            is expired as of the time we are verifying. This may cause a valid
  2636            CRL to be cached as bad. short-circuit to avoid this case. */
  2637         PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
  2638         return SECFailure;
  2641     rv = AcquireDPCache(issuer, &issuer->derSubject, dp, t, wincx, &dpcache,
  2642                         &lockedwrite);
  2643     PORT_Assert(SECSuccess == rv);
  2644     if (SECSuccess != rv)
  2646         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2647         return SECFailure;
  2649     /* now look up the certificate SN in the DP cache's CRL */
  2650     ds = DPCache_Lookup(dpcache, &cert->serialNumber, &entry);
  2651     switch (ds)
  2653         case dpcacheFoundEntry:
  2654             PORT_Assert(entry);
  2655             /* check the time if we have one */
  2656             if (entry->revocationDate.data && entry->revocationDate.len)
  2658                 PRTime revocationDate = 0;
  2659                 if (SECSuccess == DER_DecodeTimeChoice(&revocationDate,
  2660                                                &entry->revocationDate))
  2662                     /* we got a good revocation date, only consider the
  2663                        certificate revoked if the time we are inquiring about
  2664                        is past the revocation date */
  2665                     if (t>=revocationDate)
  2667                         rv = SECFailure;
  2669                     else
  2671                         status = certRevocationStatusValid;
  2674                 else
  2676                     /* invalid revocation date, consider the certificate
  2677                        permanently revoked */
  2678                     rv = SECFailure;
  2681             else
  2683                 /* no revocation date, certificate is permanently revoked */
  2684                 rv = SECFailure;
  2686             if (SECFailure == rv)
  2688                 SECStatus rv2 = CERT_FindCRLEntryReasonExten(entry, &reason);
  2689                 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
  2691             break;
  2693         case dpcacheEmpty:
  2694             /* useful for NIST policy */
  2695             status = certRevocationStatusUnknown;
  2696             break;
  2698         case dpcacheNoEntry:
  2699             status = certRevocationStatusValid;
  2700             break;
  2702         case dpcacheInvalidCacheError:
  2703             /* treat it as unknown and let the caller decide based on
  2704                the policy */
  2705             status = certRevocationStatusUnknown;
  2706             break;
  2708         default:
  2709             /* leave status as revoked */
  2710             break;
  2713     ReleaseDPCache(dpcache, lockedwrite);
  2714     if (revStatus)
  2716         *revStatus = status;
  2718     if (revReason)
  2720         *revReason = reason;
  2722     return rv;
  2725 /* check CRL revocation status of given certificate and issuer */
  2726 SECStatus
  2727 CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer,
  2728               const SECItem* dp, PRTime t, void* wincx)
  2730     return cert_CheckCertRevocationStatus(cert, issuer, dp, t, wincx,
  2731                                           NULL, NULL);
  2734 /* retrieve full CRL object that best matches the cache status */
  2735 CERTSignedCrl *
  2736 SEC_FindCrlByName(CERTCertDBHandle *handle, SECItem *crlKey, int type)
  2738     CERTSignedCrl* acrl = NULL;
  2739     CRLDPCache* dpcache = NULL;
  2740     SECStatus rv = SECSuccess;
  2741     PRBool writeLocked = PR_FALSE;
  2743     if (!crlKey)
  2745         PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2746         return NULL;
  2749     rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &dpcache, &writeLocked);
  2750     if (SECSuccess == rv)
  2752         acrl = GetBestCRL(dpcache, PR_TRUE); /* decode entries, because
  2753         SEC_FindCrlByName always returned fully decoded CRLs in the past */
  2754         ReleaseDPCache(dpcache, writeLocked);
  2756     return acrl;
  2759 /* invalidate the CRL cache for a given issuer, which forces a refetch of
  2760    CRL objects from PKCS#11 tokens */
  2761 void CERT_CRLCacheRefreshIssuer(CERTCertDBHandle* dbhandle, SECItem* crlKey)
  2763     CRLDPCache* cache = NULL;
  2764     SECStatus rv = SECSuccess;
  2765     PRBool writeLocked = PR_FALSE;
  2766     PRBool readlocked;
  2768     (void) dbhandle; /* silence compiler warnings */
  2770     /* XCRL we will need to refresh all the DPs of the issuer in the future,
  2771             not just the default one */
  2772     rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &cache, &writeLocked);
  2773     if (SECSuccess != rv)
  2775         return;
  2777     /* we need to invalidate the DPCache here */
  2778     readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
  2779     DPCache_LockWrite();
  2780     cache->refresh = PR_TRUE;
  2781     DPCache_UnlockWrite();
  2782     ReleaseDPCache(cache, writeLocked);
  2783     return;
  2786 /* add the specified RAM CRL object to the cache */
  2787 SECStatus CERT_CacheCRL(CERTCertDBHandle* dbhandle, SECItem* newdercrl)
  2789     CRLDPCache* cache = NULL;
  2790     SECStatus rv = SECSuccess;
  2791     PRBool writeLocked = PR_FALSE;
  2792     PRBool readlocked;
  2793     CachedCrl* returned = NULL;
  2794     PRBool added = PR_FALSE;
  2795     CERTSignedCrl* newcrl = NULL;
  2796     int realerror = 0;
  2798     if (!dbhandle || !newdercrl)
  2800         PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2801         return SECFailure;
  2804     /* first decode the DER CRL to make sure it's OK */
  2805     newcrl = CERT_DecodeDERCrlWithFlags(NULL, newdercrl, SEC_CRL_TYPE,
  2806                                         CRL_DECODE_DONT_COPY_DER |
  2807                                         CRL_DECODE_SKIP_ENTRIES);
  2809     if (!newcrl)
  2811         return SECFailure;
  2814     /* XXX check if it has IDP extension. If so, do not proceed and set error */
  2816     rv = AcquireDPCache(NULL,
  2817                         &newcrl->crl.derName,
  2818                         NULL, 0, NULL, &cache, &writeLocked);
  2819     if (SECSuccess == rv)
  2821         readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
  2823         rv = CachedCrl_Create(&returned, newcrl, CRL_OriginExplicit);
  2824         if (SECSuccess == rv && returned)
  2826             DPCache_LockWrite();
  2827             rv = DPCache_AddCRL(cache, returned, &added);
  2828             if (PR_TRUE != added)
  2830                 realerror = PORT_GetError();
  2831                 CachedCrl_Destroy(returned);
  2832                 returned = NULL;
  2834             DPCache_UnlockWrite();
  2837         ReleaseDPCache(cache, writeLocked);
  2839         if (!added)
  2841             rv = SECFailure;
  2844     SEC_DestroyCrl(newcrl); /* free the CRL. Either it got added to the cache
  2845         and the refcount got bumped, or not, and thus we need to free its
  2846         RAM */
  2847     if (realerror)
  2849         PORT_SetError(realerror);
  2851     return rv;
  2854 /* remove the specified RAM CRL object from the cache */
  2855 SECStatus CERT_UncacheCRL(CERTCertDBHandle* dbhandle, SECItem* olddercrl)
  2857     CRLDPCache* cache = NULL;
  2858     SECStatus rv = SECSuccess;
  2859     PRBool writeLocked = PR_FALSE;
  2860     PRBool readlocked;
  2861     PRBool removed = PR_FALSE;
  2862     PRUint32 i;
  2863     CERTSignedCrl* oldcrl = NULL;
  2865     if (!dbhandle || !olddercrl)
  2867         PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2868         return SECFailure;
  2871     /* first decode the DER CRL to make sure it's OK */
  2872     oldcrl = CERT_DecodeDERCrlWithFlags(NULL, olddercrl, SEC_CRL_TYPE,
  2873                                         CRL_DECODE_DONT_COPY_DER |
  2874                                         CRL_DECODE_SKIP_ENTRIES);
  2876     if (!oldcrl)
  2878         /* if this DER CRL can't decode, it can't be in the cache */
  2879         return SECFailure;
  2882     rv = AcquireDPCache(NULL,
  2883                         &oldcrl->crl.derName,
  2884                         NULL, 0, NULL, &cache, &writeLocked);
  2885     if (SECSuccess == rv)
  2887         CachedCrl* returned = NULL;
  2889         readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
  2891         rv = CachedCrl_Create(&returned, oldcrl, CRL_OriginExplicit);
  2892         if (SECSuccess == rv && returned)
  2894             DPCache_LockWrite();
  2895             for (i=0;i<cache->ncrls;i++)
  2897                 PRBool dupe = PR_FALSE, updated = PR_FALSE;
  2898                 rv = CachedCrl_Compare(returned, cache->crls[i],
  2899                                                       &dupe, &updated);
  2900                 if (SECSuccess != rv)
  2902                     PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  2903                     break;
  2905                 if (PR_TRUE == dupe)
  2907                     rv = DPCache_RemoveCRL(cache, i); /* got a match */
  2908                     if (SECSuccess == rv) {
  2909                         cache->mustchoose = PR_TRUE;
  2910                         removed = PR_TRUE;
  2912                     break;
  2916             DPCache_UnlockWrite();
  2918             if (SECSuccess != CachedCrl_Destroy(returned) ) {
  2919                 rv = SECFailure;
  2923         ReleaseDPCache(cache, writeLocked);
  2925     if (SECSuccess != SEC_DestroyCrl(oldcrl) ) { 
  2926         /* need to do this because object is refcounted */
  2927         rv = SECFailure;
  2929     if (SECSuccess == rv && PR_TRUE != removed)
  2931         PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
  2933     return rv;
  2936 SECStatus cert_AcquireNamedCRLCache(NamedCRLCache** returned)
  2938     PORT_Assert(returned);
  2939     if (!namedCRLCache.lock)
  2941         PORT_Assert(0);
  2942         return SECFailure;
  2944     PR_Lock(namedCRLCache.lock);
  2945     *returned = &namedCRLCache;
  2946     return SECSuccess;
  2949 /* This must be called only while cache is acquired, and the entry is only
  2950  * valid until cache is released.
  2951  */
  2952 SECStatus cert_FindCRLByGeneralName(NamedCRLCache* ncc,
  2953                                     const SECItem* canonicalizedName,
  2954                                     NamedCRLCacheEntry** retEntry)
  2956     if (!ncc || !canonicalizedName || !retEntry)
  2958         PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2959         return SECFailure;
  2961     *retEntry = (NamedCRLCacheEntry*) PL_HashTableLookup(namedCRLCache.entries,
  2962                                          (void*) canonicalizedName);
  2963     return SECSuccess;
  2966 SECStatus cert_ReleaseNamedCRLCache(NamedCRLCache* ncc)
  2968     if (!ncc)
  2970         return SECFailure;
  2972     if (!ncc->lock)
  2974         PORT_Assert(0);
  2975         return SECFailure;
  2977     PR_Unlock(namedCRLCache.lock);
  2978     return SECSuccess;
  2981 /* creates new named cache entry from CRL, and tries to add it to CRL cache */
  2982 static SECStatus addCRLToCache(CERTCertDBHandle* dbhandle, SECItem* crl,
  2983                                     const SECItem* canonicalizedName,
  2984                                     NamedCRLCacheEntry** newEntry)
  2986     SECStatus rv = SECSuccess;
  2987     NamedCRLCacheEntry* entry = NULL;
  2989     /* create new named entry */
  2990     if (SECSuccess != NamedCRLCacheEntry_Create(newEntry) || !*newEntry)
  2992         /* no need to keep unused CRL around */
  2993         SECITEM_ZfreeItem(crl, PR_TRUE);
  2994         return SECFailure;
  2996     entry = *newEntry;
  2997     entry->crl = crl; /* named CRL cache owns DER */
  2998     entry->lastAttemptTime = PR_Now();
  2999     entry->canonicalizedName = SECITEM_DupItem(canonicalizedName);
  3000     if (!entry->canonicalizedName)
  3002         rv = NamedCRLCacheEntry_Destroy(entry); /* destroys CRL too */
  3003         PORT_Assert(SECSuccess == rv);
  3004         return SECFailure;
  3006     /* now, attempt to insert CRL into CRL cache */
  3007     if (SECSuccess == CERT_CacheCRL(dbhandle, entry->crl))
  3009         entry->inCRLCache = PR_TRUE;
  3010         entry->successfulInsertionTime = entry->lastAttemptTime;
  3012     else
  3014         switch (PR_GetError())
  3016             case SEC_ERROR_CRL_ALREADY_EXISTS:
  3017                 entry->dupe = PR_TRUE;
  3018                 break;
  3020             case SEC_ERROR_BAD_DER:
  3021                 entry->badDER = PR_TRUE;
  3022                 break;
  3024             /* all other reasons */
  3025             default:
  3026                 entry->unsupported = PR_TRUE;
  3027                 break;
  3029         rv = SECFailure;
  3030         /* no need to keep unused CRL around */
  3031         SECITEM_ZfreeItem(entry->crl, PR_TRUE);
  3032         entry->crl = NULL;
  3034     return rv;
  3037 /* take ownership of CRL, and insert it into the named CRL cache
  3038  * and indexed CRL cache
  3039  */
  3040 SECStatus cert_CacheCRLByGeneralName(CERTCertDBHandle* dbhandle, SECItem* crl,
  3041                                      const SECItem* canonicalizedName)
  3043     NamedCRLCacheEntry* oldEntry, * newEntry = NULL;
  3044     NamedCRLCache* ncc = NULL;
  3045     SECStatus rv = SECSuccess, rv2;
  3047     PORT_Assert(namedCRLCache.lock);
  3048     PORT_Assert(namedCRLCache.entries);
  3050     if (!crl || !canonicalizedName)
  3052         PORT_Assert(0);
  3053         PORT_SetError(SEC_ERROR_INVALID_ARGS);
  3054         return SECFailure;
  3057     rv = cert_AcquireNamedCRLCache(&ncc);
  3058     PORT_Assert(SECSuccess == rv);
  3059     if (SECSuccess != rv)
  3061         SECITEM_ZfreeItem(crl, PR_TRUE);
  3062         return SECFailure;
  3064     rv = cert_FindCRLByGeneralName(ncc, canonicalizedName, &oldEntry);
  3065     PORT_Assert(SECSuccess == rv);
  3066     if (SECSuccess != rv)
  3068         rv = cert_ReleaseNamedCRLCache(ncc);
  3069         SECITEM_ZfreeItem(crl, PR_TRUE);
  3070         return SECFailure;
  3072     if (SECSuccess == addCRLToCache(dbhandle, crl, canonicalizedName,
  3073                                     &newEntry) )
  3075         if (!oldEntry)
  3077             /* add new good entry to the hash table */
  3078             if (NULL == PL_HashTableAdd(namedCRLCache.entries,
  3079                                         (void*) newEntry->canonicalizedName,
  3080                                         (void*) newEntry))
  3082                 PORT_Assert(0);
  3083                 rv2 = NamedCRLCacheEntry_Destroy(newEntry);
  3084                 PORT_Assert(SECSuccess == rv2);
  3085                 rv = SECFailure;
  3088         else
  3090             PRBool removed;
  3091             /* remove the old CRL from the cache if needed */
  3092             if (oldEntry->inCRLCache)
  3094                 rv = CERT_UncacheCRL(dbhandle, oldEntry->crl);
  3095                 PORT_Assert(SECSuccess == rv);
  3097             removed = PL_HashTableRemove(namedCRLCache.entries,
  3098                                       (void*) oldEntry->canonicalizedName);
  3099             PORT_Assert(removed);
  3100             if (!removed)
  3102                 rv = SECFailure;
  3103 		/* leak old entry since we couldn't remove it from the hash table */
  3105             else
  3107                 rv2 = NamedCRLCacheEntry_Destroy(oldEntry);
  3108                 PORT_Assert(SECSuccess == rv2);
  3110             if (NULL == PL_HashTableAdd(namedCRLCache.entries,
  3111                                       (void*) newEntry->canonicalizedName,
  3112                                       (void*) newEntry))
  3114                 PORT_Assert(0);
  3115                 rv = SECFailure;
  3118     } else
  3120         /* error adding new CRL to cache */
  3121         if (!oldEntry)
  3123             /* no old cache entry, use the new one even though it's bad */
  3124             if (NULL == PL_HashTableAdd(namedCRLCache.entries,
  3125                                         (void*) newEntry->canonicalizedName,
  3126                                         (void*) newEntry))
  3128                 PORT_Assert(0);
  3129                 rv = SECFailure;
  3132         else
  3134             if (oldEntry->inCRLCache)
  3136                 /* previous cache entry was good, keep it and update time */
  3137                 oldEntry-> lastAttemptTime = newEntry->lastAttemptTime;
  3138                 /* throw away new bad entry */
  3139                 rv = NamedCRLCacheEntry_Destroy(newEntry);
  3140                 PORT_Assert(SECSuccess == rv);
  3142             else
  3144                 /* previous cache entry was bad, just replace it */
  3145                 PRBool removed = PL_HashTableRemove(namedCRLCache.entries,
  3146                                           (void*) oldEntry->canonicalizedName);
  3147                 PORT_Assert(removed);
  3148                 if (!removed)
  3150 		    /* leak old entry since we couldn't remove it from the hash table */
  3151                     rv = SECFailure;
  3153                 else
  3155                     rv2 = NamedCRLCacheEntry_Destroy(oldEntry);
  3156                     PORT_Assert(SECSuccess == rv2);
  3158                 if (NULL == PL_HashTableAdd(namedCRLCache.entries,
  3159                                           (void*) newEntry->canonicalizedName,
  3160                                           (void*) newEntry))
  3162                     PORT_Assert(0);
  3163                     rv = SECFailure;
  3168     rv2 = cert_ReleaseNamedCRLCache(ncc);
  3169     PORT_Assert(SECSuccess == rv2);
  3171     return rv;
  3174 static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl,
  3175                                   CRLOrigin origin)
  3177     CachedCrl* newcrl = NULL;
  3178     if (!returned)
  3180         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  3181         return SECFailure;
  3183     newcrl = PORT_ZAlloc(sizeof(CachedCrl));
  3184     if (!newcrl)
  3186         return SECFailure;
  3188     newcrl->crl = SEC_DupCrl(crl);
  3189     newcrl->origin = origin;
  3190     *returned = newcrl;
  3191     return SECSuccess;
  3194 /* empty the cache content */
  3195 static SECStatus CachedCrl_Depopulate(CachedCrl* crl)
  3197     if (!crl)
  3199         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  3200         return SECFailure;
  3202      /* destroy the hash table */
  3203     if (crl->entries)
  3205         PL_HashTableDestroy(crl->entries);
  3206         crl->entries = NULL;
  3209     /* free the pre buffer */
  3210     if (crl->prebuffer)
  3212         PreAllocator_Destroy(crl->prebuffer);
  3213         crl->prebuffer = NULL;
  3215     return SECSuccess;
  3218 static SECStatus CachedCrl_Destroy(CachedCrl* crl)
  3220     if (!crl)
  3222         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  3223         return SECFailure;
  3225     CachedCrl_Depopulate(crl);
  3226     SEC_DestroyCrl(crl->crl);
  3227     PORT_Free(crl);
  3228     return SECSuccess;
  3231 /* create hash table of CRL entries */
  3232 static SECStatus CachedCrl_Populate(CachedCrl* crlobject)
  3234     SECStatus rv = SECFailure;
  3235     CERTCrlEntry** crlEntry = NULL;
  3236     PRUint32 numEntries = 0;
  3238     if (!crlobject)
  3240         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  3241         return SECFailure;
  3243     /* complete the entry decoding . XXX thread-safety of CRL object */
  3244     rv = CERT_CompleteCRLDecodeEntries(crlobject->crl);
  3245     if (SECSuccess != rv)
  3247         crlobject->unbuildable = PR_TRUE; /* don't try to build this again */
  3248         return SECFailure;
  3251     if (crlobject->entries && crlobject->prebuffer)
  3253         /* cache is already built */
  3254         return SECSuccess;
  3257     /* build the hash table from the full CRL */    
  3258     /* count CRL entries so we can pre-allocate space for hash table entries */
  3259     for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
  3260          crlEntry++)
  3262         numEntries++;
  3264     crlobject->prebuffer = PreAllocator_Create(numEntries*sizeof(PLHashEntry));
  3265     PORT_Assert(crlobject->prebuffer);
  3266     if (!crlobject->prebuffer)
  3268         return SECFailure;
  3270     /* create a new hash table */
  3271     crlobject->entries = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
  3272                          PL_CompareValues, &preAllocOps, crlobject->prebuffer);
  3273     PORT_Assert(crlobject->entries);
  3274     if (!crlobject->entries)
  3276         return SECFailure;
  3278     /* add all serial numbers to the hash table */
  3279     for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
  3280          crlEntry++)
  3282         PL_HashTableAdd(crlobject->entries, &(*crlEntry)->serialNumber,
  3283                         *crlEntry);
  3286     return SECSuccess;
  3289 /* returns true if there are CRLs from PKCS#11 slots */
  3290 static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache)
  3292     PRBool answer = PR_FALSE;
  3293     PRUint32 i;
  3294     for (i=0;i<cache->ncrls;i++)
  3296         if (cache->crls[i] && (CRL_OriginToken == cache->crls[i]->origin) )
  3298             answer = PR_TRUE;
  3299             break;
  3302     return answer;
  3305 /* are these CRLs the same, as far as the cache is concerned ? */
  3306 /* are these CRLs the same token object but with different DER ?
  3307    This can happen if the DER CRL got updated in the token, but the PKCS#11
  3308    object ID did not change. NSS softoken has the unfortunate property to
  3309    never change the object ID for CRL objects. */
  3310 static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe,
  3311                                 PRBool* isUpdated)
  3313     PORT_Assert(a);
  3314     PORT_Assert(b);
  3315     PORT_Assert(isDupe);
  3316     PORT_Assert(isUpdated);
  3317     if (!a || !b || !isDupe || !isUpdated || !a->crl || !b->crl)
  3319         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  3320         return SECFailure;
  3323     *isDupe = *isUpdated = PR_FALSE;
  3325     if (a == b)
  3327         /* dupe */
  3328         *isDupe = PR_TRUE;
  3329         *isUpdated = PR_FALSE;
  3330         return SECSuccess;
  3332     if (b->origin != a->origin)
  3334         /* CRLs of different origins are not considered dupes,
  3335            and can't be updated either */
  3336         return SECSuccess;
  3338     if (CRL_OriginToken == b->origin)
  3340         /* for token CRLs, slot and PKCS#11 object handle must match for CRL
  3341            to truly be a dupe */
  3342         if ( (b->crl->slot == a->crl->slot) &&
  3343              (b->crl->pkcs11ID == a->crl->pkcs11ID) )
  3345             /* ASN.1 DER needs to match for dupe check */
  3346             /* could optimize by just checking a few fields like thisUpdate */
  3347             if ( SECEqual == SECITEM_CompareItem(b->crl->derCrl,
  3348                                                  a->crl->derCrl) )
  3350                 *isDupe = PR_TRUE;
  3352             else
  3354                 *isUpdated = PR_TRUE;
  3357         return SECSuccess;
  3359     if (CRL_OriginExplicit == b->origin)
  3361         /* We need to make sure this is the same object that the user provided
  3362            to CERT_CacheCRL previously. That API takes a SECItem*, thus, we
  3363            just do a pointer comparison here.
  3364         */
  3365         if (b->crl->derCrl == a->crl->derCrl)
  3367             *isDupe = PR_TRUE;
  3370     return SECSuccess;

mercurial