/* 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); }