diff options
Diffstat (limited to 'security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c')
-rw-r--r-- | security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c | 1068 |
1 files changed, 1068 insertions, 0 deletions
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c new file mode 100644 index 000000000..b83db357a --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c @@ -0,0 +1,1068 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_crl.c + * + * CRL Function Definitions + * + */ + +#include "pkix_pl_crl.h" +#include "certxutl.h" + +extern PKIX_PL_HashTable *cachedCrlSigTable; + +/* --Private-CRL-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_CRL_GetVersion + * DESCRIPTION: + * + * Retrieves the version of the CRL pointed to by "crl" and stores it at + * "pVersion". The version number will either be 0 or 1 (corresponding to + * v1 or v2, respectively). + * + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + * + * PARAMETERS: + * "crl" + * Address of CRL whose version is to be stored. Must be non-NULL. + * "pVersion" + * Address where a version will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CRL Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_CRL_GetVersion( + PKIX_PL_CRL *crl, + PKIX_UInt32 *pVersion, + void *plContext) +{ + PKIX_UInt32 myVersion; + + PKIX_ENTER(CRL, "pkix_pl_CRL_GetVersion"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pVersion); + + PKIX_NULLCHECK_ONE(crl->nssSignedCrl->crl.version.data); + + myVersion = *(crl->nssSignedCrl->crl.version.data); + + if (myVersion > 1) { + PKIX_ERROR(PKIX_VERSIONVALUEMUSTBEV1ORV2); + } + + *pVersion = myVersion; + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: PKIX_PL_CRL_GetCRLNumber (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_GetCRLNumber( + PKIX_PL_CRL *crl, + PKIX_PL_BigInt **pCrlNumber, + void *plContext) +{ + PKIX_PL_BigInt *crlNumber = NULL; + SECItem nssCrlNumber; + PLArenaPool *arena = NULL; + SECStatus status; + PKIX_UInt32 length = 0; + char *bytes = NULL; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_GetCRLNumber"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pCrlNumber); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + if (!crl->crlNumberAbsent && crl->crlNumber == NULL) { + + PKIX_OBJECT_LOCK(crl); + + if (!crl->crlNumberAbsent && crl->crlNumber == NULL) { + + nssCrlNumber.type = 0; + nssCrlNumber.len = 0; + nssCrlNumber.data = NULL; + + PKIX_CRL_DEBUG("\t\tCalling PORT_NewArena).\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + PKIX_CRL_DEBUG("\t\tCalling CERT_FindCRLNumberExten\n"); + status = CERT_FindCRLNumberExten + (arena, &crl->nssSignedCrl->crl, &nssCrlNumber); + + if (status == SECSuccess) { + /* Get data in bytes then convert to bigint */ + length = nssCrlNumber.len; + bytes = (char *)nssCrlNumber.data; + + PKIX_CHECK(pkix_pl_BigInt_CreateWithBytes + (bytes, length, &crlNumber, plContext), + PKIX_BIGINTCREATEWITHBYTESFAILED); + + /* arena release does the job + PKIX_CRL_DEBUG("\t\tCalling SECITEM_FreeItem\n"); + SECITEM_FreeItem(&nssCrlNumber, PKIX_FALSE); + */ + crl->crlNumber = crlNumber; + + } else { + + crl->crlNumberAbsent = PKIX_TRUE; + } + } + + PKIX_OBJECT_UNLOCK(crl); + + } + + PKIX_INCREF(crl->crlNumber); + + *pCrlNumber = crl->crlNumber; + +cleanup: + + if (arena){ + PKIX_CRL_DEBUG("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + } + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_GetSignatureAlgId + * + * DESCRIPTION: + * Retrieves a pointer to the OID that represents the signature algorithm of + * the CRL pointed to by "crl" and stores it at "pSignatureAlgId". + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + * + * PARAMETERS: + * "crl" + * Address of CRL whose signature algorithm OID is to be stored. + * Must be non-NULL. + * "pSignatureAlgId" + * Address where object pointer will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CRL Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_CRL_GetSignatureAlgId( + PKIX_PL_CRL *crl, + PKIX_PL_OID **pSignatureAlgId, + void *plContext) +{ + PKIX_PL_OID *signatureAlgId = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_GetSignatureAlgId"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pSignatureAlgId); + + /* if we don't have a cached copy from before, we create one */ + if (crl->signatureAlgId == NULL){ + PKIX_OBJECT_LOCK(crl); + if (crl->signatureAlgId == NULL){ + CERTCrl *nssCrl = &(crl->nssSignedCrl->crl); + SECAlgorithmID *algorithm = &nssCrl->signatureAlg; + SECItem *algBytes = &algorithm->algorithm; + + if (!algBytes->data || !algBytes->len) { + PKIX_ERROR(PKIX_OIDBYTESLENGTH0); + } + PKIX_CHECK(PKIX_PL_OID_CreateBySECItem + (algBytes, &signatureAlgId, plContext), + PKIX_OIDCREATEFAILED); + + /* save a cached copy in case it is asked for again */ + crl->signatureAlgId = signatureAlgId; + signatureAlgId = NULL; + } + PKIX_OBJECT_UNLOCK(crl); + } + PKIX_INCREF(crl->signatureAlgId); + *pSignatureAlgId = crl->signatureAlgId; +cleanup: + PKIX_DECREF(signatureAlgId); + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_GetCRLEntries + * DESCRIPTION: + * + * Retrieves a pointer to the List of CRLEntries found in the CRL pointed to + * by "crl" and stores it at "pCRLEntries". If there are no CRLEntries, + * this functions stores NULL at "pCRLEntries". + * + * PARAMETERS: + * "crl" + * Address of CRL whose CRL Entries are to be retrieved. Must be non-NULL. + * "pCRLEntries" + * Address where object pointer will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CRL Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_CRL_GetCRLEntries( + PKIX_PL_CRL *crl, + PKIX_List **pCrlEntries, + void *plContext) +{ + PKIX_List *entryList = NULL; + CERTCrl *nssCrl = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_GetCRLEntries"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pCrlEntries); + + /* if we don't have a cached copy from before, we create one */ + if (crl->crlEntryList == NULL) { + + PKIX_OBJECT_LOCK(crl); + + if (crl->crlEntryList == NULL){ + + nssCrl = &(crl->nssSignedCrl->crl); + + PKIX_CHECK(pkix_pl_CRLEntry_Create + (nssCrl->entries, &entryList, plContext), + PKIX_CRLENTRYCREATEFAILED); + + PKIX_CHECK(PKIX_List_SetImmutable + (entryList, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + crl->crlEntryList = entryList; + } + + PKIX_OBJECT_UNLOCK(crl); + + } + + PKIX_INCREF(crl->crlEntryList); + + *pCrlEntries = crl->crlEntryList; + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRL_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CRL *crl = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRL_TYPE, plContext), + PKIX_OBJECTNOTCRL); + + crl = (PKIX_PL_CRL*)object; + + PKIX_CRL_DEBUG("\t\tCalling CERT_DestroyCrl\n"); + if (crl->nssSignedCrl) { + CERT_DestroyCrl(crl->nssSignedCrl); + } + if (crl->adoptedDerCrl) { + SECITEM_FreeItem(crl->adoptedDerCrl, PR_TRUE); + } + crl->nssSignedCrl = NULL; + crl->adoptedDerCrl = NULL; + crl->crlNumberAbsent = PKIX_FALSE; + + PKIX_DECREF(crl->issuer); + PKIX_DECREF(crl->signatureAlgId); + PKIX_DECREF(crl->crlNumber); + PKIX_DECREF(crl->crlEntryList); + PKIX_DECREF(crl->critExtOids); + if (crl->derGenName) { + SECITEM_FreeItem(crl->derGenName, PR_TRUE); + } + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_ToString_Helper + * DESCRIPTION: + * + * Helper function that creates a string representation of the CRL pointed + * to by "crl" and stores it at "pString". + * + * PARAMETERS + * "crl" + * Address of CRL whose string representation is desired. + * Must be non-NULL. + * "pString" + * Address where object pointer will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CRL Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_CRL_ToString_Helper( + PKIX_PL_CRL *crl, + PKIX_PL_String **pString, + void *plContext) +{ + char *asciiFormat = NULL; + PKIX_UInt32 crlVersion = 0; + PKIX_PL_X500Name *crlIssuer = NULL; + PKIX_PL_OID *nssSignatureAlgId = NULL; + PKIX_PL_BigInt *crlNumber = NULL; + PKIX_List *crlEntryList = NULL; + PKIX_List *critExtOIDs = NULL; + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *crlIssuerString = NULL; + PKIX_PL_String *lastUpdateString = NULL; + PKIX_PL_String *nextUpdateString = NULL; + PKIX_PL_String *nssSignatureAlgIdString = NULL; + PKIX_PL_String *crlNumberString = NULL; + PKIX_PL_String *crlEntryListString = NULL; + PKIX_PL_String *critExtOIDsString = NULL; + PKIX_PL_String *crlString = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_ToString_Helper"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pString); + + asciiFormat = + "[\n" + "\tVersion: v%d\n" + "\tIssuer: %s\n" + "\tUpdate: [Last: %s\n" + "\t Next: %s]\n" + "\tSignatureAlgId: %s\n" + "\tCRL Number : %s\n" + "\n" + "\tEntry List: %s\n" + "\n" + "\tCritExtOIDs: %s\n" + "]\n"; + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + asciiFormat, + 0, + &formatString, + plContext), + PKIX_STRINGCREATEFAILED); + + /* Version */ + PKIX_CHECK(pkix_pl_CRL_GetVersion(crl, &crlVersion, plContext), + PKIX_CRLGETVERSIONFAILED); + + /* Issuer */ + PKIX_CHECK(PKIX_PL_CRL_GetIssuer(crl, &crlIssuer, plContext), + PKIX_CRLGETISSUERFAILED); + + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)crlIssuer, &crlIssuerString, plContext), + PKIX_X500NAMETOSTRINGFAILED); + + /* This update - No Date object created, use nss data directly */ + PKIX_CHECK(pkix_pl_Date_ToString_Helper + (&(crl->nssSignedCrl->crl.lastUpdate), + &lastUpdateString, + plContext), + PKIX_DATETOSTRINGHELPERFAILED); + + /* Next update - No Date object created, use nss data directly */ + PKIX_CHECK(pkix_pl_Date_ToString_Helper + (&(crl->nssSignedCrl->crl.nextUpdate), + &nextUpdateString, + plContext), + PKIX_DATETOSTRINGHELPERFAILED); + + /* Signature Algorithm Id */ + PKIX_CHECK(pkix_pl_CRL_GetSignatureAlgId + (crl, &nssSignatureAlgId, plContext), + PKIX_CRLGETSIGNATUREALGIDFAILED); + + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)nssSignatureAlgId, + &nssSignatureAlgIdString, + plContext), + PKIX_OIDTOSTRINGFAILED); + + /* CRL Number */ + PKIX_CHECK(PKIX_PL_CRL_GetCRLNumber + (crl, &crlNumber, plContext), + PKIX_CRLGETCRLNUMBERFAILED); + + PKIX_TOSTRING(crlNumber, &crlNumberString, plContext, + PKIX_BIGINTTOSTRINGFAILED); + + /* CRL Entries */ + PKIX_CHECK(pkix_pl_CRL_GetCRLEntries(crl, &crlEntryList, plContext), + PKIX_CRLGETCRLENTRIESFAILED); + + PKIX_TOSTRING(crlEntryList, &crlEntryListString, plContext, + PKIX_LISTTOSTRINGFAILED); + + /* CriticalExtensionOIDs */ + PKIX_CHECK(PKIX_PL_CRL_GetCriticalExtensionOIDs + (crl, &critExtOIDs, plContext), + PKIX_CRLGETCRITICALEXTENSIONOIDSFAILED); + + PKIX_TOSTRING(critExtOIDs, &critExtOIDsString, plContext, + PKIX_LISTTOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&crlString, + plContext, + formatString, + crlVersion + 1, + crlIssuerString, + lastUpdateString, + nextUpdateString, + nssSignatureAlgIdString, + crlNumberString, + crlEntryListString, + critExtOIDsString), + PKIX_SPRINTFFAILED); + + *pString = crlString; + +cleanup: + + PKIX_DECREF(crlIssuer); + PKIX_DECREF(nssSignatureAlgId); + PKIX_DECREF(crlNumber); + PKIX_DECREF(crlEntryList); + PKIX_DECREF(critExtOIDs); + PKIX_DECREF(crlIssuerString); + PKIX_DECREF(lastUpdateString); + PKIX_DECREF(nextUpdateString); + PKIX_DECREF(nssSignatureAlgIdString); + PKIX_DECREF(crlNumberString); + PKIX_DECREF(crlEntryListString); + PKIX_DECREF(critExtOIDsString); + PKIX_DECREF(formatString); + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRL_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *crlString = NULL; + PKIX_PL_CRL *crl = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRL_TYPE, plContext), + PKIX_OBJECTNOTCRL); + + crl = (PKIX_PL_CRL *) object; + + PKIX_CHECK(pkix_pl_CRL_ToString_Helper(crl, &crlString, plContext), + PKIX_CRLTOSTRINGHELPERFAILED); + + *pString = crlString; + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRL_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_CRL *crl = NULL; + PKIX_UInt32 certHash; + SECItem *crlDer = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRL_TYPE, plContext), + PKIX_OBJECTNOTCRL); + + crl = (PKIX_PL_CRL *)object; + if (crl->adoptedDerCrl) { + crlDer = crl->adoptedDerCrl; + } else if (crl->nssSignedCrl && crl->nssSignedCrl->derCrl) { + crlDer = crl->nssSignedCrl->derCrl; + } + if (!crlDer || !crlDer->data) { + PKIX_ERROR(PKIX_CANNOTAQUIRECRLDER); + } + + PKIX_CHECK(pkix_hash(crlDer->data, crlDer->len, + &certHash, plContext), + PKIX_ERRORINHASH); + + *pHashcode = certHash; + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRL_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CRL *firstCrl = NULL; + PKIX_PL_CRL *secondCrl = NULL; + SECItem *crlDerOne = NULL, *crlDerTwo = NULL; + PKIX_UInt32 secondType; + + PKIX_ENTER(CRL, "pkix_pl_CRL_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CRL */ + PKIX_CHECK(pkix_CheckType(firstObject, PKIX_CRL_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCRL); + + firstCrl = (PKIX_PL_CRL *)firstObject; + secondCrl = (PKIX_PL_CRL *)secondObject; + + /* + * Since we know firstObject is a CRL, if both references are + * identical, they must be equal + */ + if (firstCrl == secondCrl){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondCrl isn't a CRL, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType + ((PKIX_PL_Object *)secondCrl, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_CRL_TYPE) goto cleanup; + + if (firstCrl->adoptedDerCrl) { + crlDerOne = firstCrl->adoptedDerCrl; + } else if (firstCrl->nssSignedCrl && firstCrl->nssSignedCrl->derCrl) { + crlDerOne = firstCrl->nssSignedCrl->derCrl; + } + + if (secondCrl->adoptedDerCrl) { + crlDerTwo = secondCrl->adoptedDerCrl; + } else if (secondCrl->nssSignedCrl && secondCrl->nssSignedCrl->derCrl) { + crlDerTwo = secondCrl->nssSignedCrl->derCrl; + } + + if (SECITEM_CompareItem(crlDerOne, crlDerTwo) == SECEqual) { + *pResult = PKIX_TRUE; + } + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_RegisterSelf + * + * DESCRIPTION: + * Registers PKIX_CRL_TYPE and its related functions with systemClasses[] + * THREAD SAFETY: + * + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_pl_CRL_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry *entry = &systemClasses[PKIX_CRL_TYPE]; + + PKIX_ENTER(CRL, "pkix_pl_CRL_RegisterSelf"); + + entry->description = "CRL"; + entry->typeObjectSize = sizeof(PKIX_PL_CRL); + entry->destructor = pkix_pl_CRL_Destroy; + entry->equalsFunction = pkix_pl_CRL_Equals; + entry->hashcodeFunction = pkix_pl_CRL_Hashcode; + entry->toStringFunction = pkix_pl_CRL_ToString; + entry->duplicateFunction = pkix_duplicateImmutable; + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: PKIX_PL_CRL_VerifyUpdateTime (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_VerifyUpdateTime( + PKIX_PL_CRL *crl, + PKIX_PL_Date *date, + PKIX_Boolean *pResult, + void *plContext) +{ + PRTime timeToCheck; + PRTime nextUpdate; + PRTime lastUpdate; + SECStatus status; + CERTCrl *nssCrl = NULL; + SECItem *nextUpdateDer = NULL; + PKIX_Boolean haveNextUpdate = PR_FALSE; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_VerifyUpdateTime"); + PKIX_NULLCHECK_FOUR(crl, crl->nssSignedCrl, date, pResult); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + nssCrl = &(crl->nssSignedCrl->crl); + timeToCheck = date->nssTime; + + /* nextUpdate can be NULL. Checking before using it */ + nextUpdateDer = &nssCrl->nextUpdate; + if (nextUpdateDer->data && nextUpdateDer->len) { + haveNextUpdate = PR_TRUE; + status = DER_DecodeTimeChoice(&nextUpdate, nextUpdateDer); + if (status != SECSuccess) { + PKIX_ERROR(PKIX_DERDECODETIMECHOICEFORNEXTUPDATEFAILED); + } + } + + status = DER_DecodeTimeChoice(&lastUpdate, &(nssCrl->lastUpdate)); + if (status != SECSuccess) { + PKIX_ERROR(PKIX_DERDECODETIMECHOICEFORLASTUPDATEFAILED); + } + + if (!haveNextUpdate || nextUpdate < timeToCheck) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + if (lastUpdate <= timeToCheck) { + *pResult = PKIX_TRUE; + } else { + *pResult = PKIX_FALSE; + } + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_CreateWithSignedCRL + * DESCRIPTION: + * + * Creates a new CRL using the CERTSignedCrl pointed to by "nssSignedCrl" + * and stores it at "pCRL". If the decoding of the CERTSignedCrl fails, + * a PKIX_Error is returned. + * + * PARAMETERS: + * "nssSignedCrl" + * Address of CERTSignedCrl. Must be non-NULL. + * "adoptedDerCrl" + * SECItem ponter that if not NULL is indicating that memory used + * for der should be adopted by crl that is about to be created. + * "pCRL" + * Address where object pointer will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CRL Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_CRL_CreateWithSignedCRL( + CERTSignedCrl *nssSignedCrl, + SECItem *adoptedDerCrl, + SECItem *derGenName, + PKIX_PL_CRL **pCrl, + void *plContext) +{ + PKIX_PL_CRL *crl = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_CreateWithSignedCRL"); + PKIX_NULLCHECK_ONE(pCrl); + + /* create a PKIX_PL_CRL object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CRL_TYPE, + sizeof (PKIX_PL_CRL), + (PKIX_PL_Object **)&crl, + plContext), + PKIX_COULDNOTCREATECRLOBJECT); + + /* populate the nssSignedCrl field */ + crl->nssSignedCrl = nssSignedCrl; + crl->adoptedDerCrl = adoptedDerCrl; + crl->issuer = NULL; + crl->signatureAlgId = NULL; + crl->crlNumber = NULL; + crl->crlNumberAbsent = PKIX_FALSE; + crl->crlEntryList = NULL; + crl->critExtOids = NULL; + if (derGenName) { + crl->derGenName = + SECITEM_DupItem(derGenName); + if (!crl->derGenName) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + } + + *pCrl = crl; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(crl); + } + + PKIX_RETURN(CRL); +} + +/* --Public-CRL-Functions------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_CRL_Create (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_Create( + PKIX_PL_ByteArray *byteArray, + PKIX_PL_CRL **pCrl, + void *plContext) +{ + CERTSignedCrl *nssSignedCrl = NULL; + SECItem derItem, *derCrl = NULL; + PKIX_PL_CRL *crl = NULL; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_Create"); + PKIX_NULLCHECK_TWO(byteArray, pCrl); + + if (byteArray->length == 0){ + PKIX_ERROR(PKIX_ZEROLENGTHBYTEARRAYFORCRLENCODING); + } + derItem.type = siBuffer; + derItem.data = byteArray->array; + derItem.len = byteArray->length; + derCrl = SECITEM_DupItem(&derItem); + if (!derCrl) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + nssSignedCrl = + CERT_DecodeDERCrlWithFlags(NULL, derCrl, SEC_CRL_TYPE, + CRL_DECODE_DONT_COPY_DER | + CRL_DECODE_SKIP_ENTRIES); + if (!nssSignedCrl) { + PKIX_ERROR(PKIX_CERTDECODEDERCRLFAILED); + } + PKIX_CHECK( + pkix_pl_CRL_CreateWithSignedCRL(nssSignedCrl, derCrl, NULL, + &crl, plContext), + PKIX_CRLCREATEWITHSIGNEDCRLFAILED); + nssSignedCrl = NULL; + derCrl = NULL; + *pCrl = crl; + +cleanup: + if (derCrl) { + SECITEM_FreeItem(derCrl, PR_TRUE); + } + if (nssSignedCrl) { + SEC_DestroyCrl(nssSignedCrl); + } + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: PKIX_PL_CRL_GetIssuer (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_GetIssuer( + PKIX_PL_CRL *crl, + PKIX_PL_X500Name **pCRLIssuer, + void *plContext) +{ + PKIX_PL_String *crlString = NULL; + PKIX_PL_X500Name *issuer = NULL; + SECItem *derIssuerName = NULL; + CERTName *issuerName = NULL; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_GetIssuer"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pCRLIssuer); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + /* if we don't have a cached copy from before, we create one */ + if (crl->issuer == NULL){ + + PKIX_OBJECT_LOCK(crl); + + if (crl->issuer == NULL) { + + issuerName = &crl->nssSignedCrl->crl.name; + derIssuerName = &crl->nssSignedCrl->crl.derName; + + PKIX_CHECK( + PKIX_PL_X500Name_CreateFromCERTName(derIssuerName, + issuerName, + &issuer, + plContext), + PKIX_X500NAMECREATEFROMCERTNAMEFAILED); + + /* save a cached copy in case it is asked for again */ + crl->issuer = issuer; + } + + PKIX_OBJECT_UNLOCK(crl); + + } + + PKIX_INCREF(crl->issuer); + + *pCRLIssuer = crl->issuer; + +cleanup: + + PKIX_DECREF(crlString); + + PKIX_RETURN(CRL); +} + + +/* + * FUNCTION: PKIX_PL_CRL_GetCriticalExtensionOIDs + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_GetCriticalExtensionOIDs( + PKIX_PL_CRL *crl, + PKIX_List **pExtensions, /* list of PKIX_PL_OID */ + void *plContext) +{ + PKIX_List *oidsList = NULL; + CERTCertExtension **extensions = NULL; + CERTCrl *nssSignedCrl = NULL; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_GetCriticalExtensionOIDs"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pExtensions); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + /* if we don't have a cached copy from before, we create one */ + if (crl->critExtOids == NULL) { + + PKIX_OBJECT_LOCK(crl); + + nssSignedCrl = &(crl->nssSignedCrl->crl); + extensions = nssSignedCrl->extensions; + + if (crl->critExtOids == NULL) { + + PKIX_CHECK(pkix_pl_OID_GetCriticalExtensionOIDs + (extensions, &oidsList, plContext), + PKIX_GETCRITICALEXTENSIONOIDSFAILED); + + crl->critExtOids = oidsList; + } + + PKIX_OBJECT_UNLOCK(crl); + + } + + /* We should return a copy of the List since this list changes */ + PKIX_DUPLICATE(crl->critExtOids, pExtensions, plContext, + PKIX_OBJECTDUPLICATELISTFAILED); + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: PKIX_PL_CRL_VerifySignature (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_VerifySignature( + PKIX_PL_CRL *crl, + PKIX_PL_PublicKey *pubKey, + void *plContext) +{ + PKIX_PL_CRL *cachedCrl = NULL; + PKIX_Error *verifySig = NULL; + PKIX_Error *cachedSig = NULL; + PKIX_Boolean crlEqual = PKIX_FALSE; + PKIX_Boolean crlInHash= PKIX_FALSE; + CERTSignedCrl *nssSignedCrl = NULL; + SECKEYPublicKey *nssPubKey = NULL; + CERTSignedData *tbsCrl = NULL; + void* wincx = NULL; + SECStatus status; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_VerifySignature"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pubKey); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + verifySig = PKIX_PL_HashTable_Lookup + (cachedCrlSigTable, + (PKIX_PL_Object *) pubKey, + (PKIX_PL_Object **) &cachedCrl, + plContext); + + if (cachedCrl != NULL && verifySig == NULL) { + /* Cached Signature Table lookup succeed */ + PKIX_EQUALS(crl, cachedCrl, &crlEqual, plContext, + PKIX_OBJECTEQUALSFAILED); + if (crlEqual == PKIX_TRUE) { + goto cleanup; + } + /* Different PubKey may hash to same value, skip add */ + crlInHash = PKIX_TRUE; + } + + nssSignedCrl = crl->nssSignedCrl; + tbsCrl = &nssSignedCrl->signatureWrap; + + PKIX_CRL_DEBUG("\t\tCalling SECKEY_ExtractPublicKey\n"); + nssPubKey = SECKEY_ExtractPublicKey(pubKey->nssSPKI); + if (!nssPubKey){ + PKIX_ERROR(PKIX_SECKEYEXTRACTPUBLICKEYFAILED); + } + + PKIX_CHECK(pkix_pl_NssContext_GetWincx + ((PKIX_PL_NssContext *)plContext, &wincx), + PKIX_NSSCONTEXTGETWINCXFAILED); + + PKIX_CRL_DEBUG("\t\tCalling CERT_VerifySignedDataWithPublicKey\n"); + status = CERT_VerifySignedDataWithPublicKey(tbsCrl, nssPubKey, wincx); + + if (status != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + PKIX_ERROR(PKIX_SIGNATUREDIDNOTVERIFYWITHTHEPUBLICKEY); + } + + if (crlInHash == PKIX_FALSE) { + cachedSig = PKIX_PL_HashTable_Add + (cachedCrlSigTable, + (PKIX_PL_Object *) pubKey, + (PKIX_PL_Object *) crl, + plContext); + + if (cachedSig != NULL) { + PKIX_DEBUG("PKIX_PL_HashTable_Add skipped: entry existed\n"); + } + } + +cleanup: + + if (nssPubKey){ + PKIX_CRL_DEBUG("\t\tCalling SECKEY_DestroyPublicKey\n"); + SECKEY_DestroyPublicKey(nssPubKey); + nssPubKey = NULL; + } + + PKIX_DECREF(cachedCrl); + PKIX_DECREF(verifySig); + PKIX_DECREF(cachedSig); + + PKIX_RETURN(CRL); +} + +PKIX_Error* +PKIX_PL_CRL_ReleaseDerCrl(PKIX_PL_CRL *crl, + SECItem **derCrl, + void *plContext) +{ + PKIX_ENTER(CRL, "PKIX_PL_CRL_ReleaseDerCrl"); + *derCrl = crl->adoptedDerCrl; + crl->adoptedDerCrl = NULL; + + PKIX_RETURN(CRL); +} + +PKIX_Error* +PKIX_PL_CRL_AdoptDerCrl(PKIX_PL_CRL *crl, + SECItem *derCrl, + void *plContext) +{ + PKIX_ENTER(CRL, "PKIX_PL_CRL_AquireDerCrl"); + if (crl->adoptedDerCrl) { + PKIX_ERROR(PKIX_CANNOTAQUIRECRLDER); + } + crl->adoptedDerCrl = derCrl; +cleanup: + PKIX_RETURN(CRL); +} |