/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the PKIX-C library. * * The Initial Developer of the Original Code is * Sun Microsystems, Inc. * Portions created by the Initial Developer are * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. * * Contributor(s): * Sun Microsystems, Inc. * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * pkix_pl_crl.c * * CRL Function Definitions * */ #include "pkix_pl_crl.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); 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) { CERTCrl *nssCrl = NULL; PKIX_PL_OID *signatureAlgId = NULL; SECAlgorithmID algorithm; SECItem algBytes; char *asciiOID = 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){ nssCrl = &(crl->nssSignedCrl->crl); algorithm = nssCrl->signatureAlg; algBytes = algorithm.algorithm; PKIX_NULLCHECK_ONE(algBytes.data); if (algBytes.len == 0) { PKIX_ERROR_FATAL(PKIX_OIDBYTESLENGTH0); } PKIX_CHECK(pkix_pl_oidBytes2Ascii (&algBytes, &asciiOID, plContext), PKIX_OIDBYTES2ASCIIFAILED); PKIX_CHECK(PKIX_PL_OID_Create (asciiOID, &signatureAlgId, plContext), PKIX_OIDCREATEFAILED); /* save a cached copy in case it is asked for again */ crl->signatureAlgId = signatureAlgId; } PKIX_OBJECT_UNLOCK(crl); } PKIX_INCREF(crl->signatureAlgId); *pSignatureAlgId = crl->signatureAlgId; cleanup: PKIX_FREE(asciiOID); 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_NULLCHECK_ONE(crl->nssSignedCrl); PKIX_CRL_DEBUG("\t\tCalling CERT_DestroyCrl\n"); CERT_DestroyCrl(crl->nssSignedCrl); crl->nssSignedCrl = 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); 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; 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; unsigned char *derBytes = NULL; PKIX_UInt32 derLength; PKIX_UInt32 certHash; 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; PKIX_NULLCHECK_TWO(crl->nssSignedCrl, crl->nssSignedCrl->derCrl); derBytes = (crl->nssSignedCrl->derCrl)->data; derLength = (crl->nssSignedCrl->derCrl)->len; PKIX_NULLCHECK_ONE(derBytes); PKIX_CHECK(pkix_hash(derBytes, derLength, &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; 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; /* Compare DER Bytes */ PKIX_NULLCHECK_TWO (firstCrl->nssSignedCrl, firstCrl->nssSignedCrl->derCrl); PKIX_NULLCHECK_TWO (secondCrl->nssSignedCrl, secondCrl->nssSignedCrl->derCrl); PKIX_CRL_DEBUG("\t\tCalling SECITEM_CompareItem on derCrl\n"); if (SECITEM_CompareItem(firstCrl->nssSignedCrl->derCrl, secondCrl->nssSignedCrl->derCrl) == 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; PKIX_ENTER(CRL, "pkix_pl_CRL_RegisterSelf"); entry.description = "CRL"; entry.objCounter = 0; 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.comparator = NULL; entry.duplicateFunction = pkix_duplicateImmutable; systemClasses[PKIX_CRL_TYPE] = entry; 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); nssCrl = &(crl->nssSignedCrl->crl); PKIX_CRL_DEBUG("\t\tCalling DER_DecodeTimeChoice on date\n"); status = DER_DecodeTimeChoice(&timeToCheck, &(date->nssTime)); if (status != SECSuccess) { PKIX_ERROR(PKIX_DERDECODETIMECHOICEFAILED); } /* 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. * "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, PKIX_PL_CRL **pCrl, void *plContext) { SECStatus status; PKIX_PL_CRL *crl = NULL; PKIX_ENTER(CRL, "pkix_pl_CRL_CreateWithSignedCRL"); PKIX_NULLCHECK_TWO(nssSignedCrl, 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; PKIX_CRL_DEBUG("\t\tCalling CERT_CompleteCRLDecodeEntries\n"); status = CERT_CompleteCRLDecodeEntries(crl->nssSignedCrl); if (status != SECSuccess) { PKIX_ERROR(PKIX_CERTCOMPLETECRLDECODEDENTRIESFAILED); } crl->issuer = NULL; crl->signatureAlgId = NULL; crl->crlNumber = NULL; crl->crlNumberAbsent = PKIX_FALSE; crl->crlEntryList = NULL; crl->critExtOids = NULL; *pCrl = crl; cleanup: if (PKIX_ERROR_RECEIVED){ PKIX_DECREF(crl); } PKIX_RETURN(CRL); } /* * FUNCTION: pkix_pl_CRL_CreateToList * DESCRIPTION: * * This function decodes a DER-encoded Certificate Revocation List pointed to * by "derCrlItem", adding the resulting PKIX_PL_CRL, if the decoding was * successful, to the List (possibly empty) pointed to by "crlList". * * PARAMETERS: * "derCrlItem" * The address of the SECItem containing the DER-encoded Certificate * Revocation List. Must be non-NULL. * "crlList" * The address of the List to which the decoded CRL is added. May be * empty, but 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 CertStore 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_CreateToList( SECItem *derCrlItem, PKIX_List *crlList, void *plContext) { CERTSignedCrl *nssCrl = NULL; PKIX_PL_CRL *crl = NULL; PKIX_ENTER(CRL, "pkix_pl_CRL_CreateToList"); PKIX_NULLCHECK_TWO(derCrlItem, crlList); nssCrl = CERT_DecodeDERCrl(NULL, derCrlItem, SEC_CRL_TYPE); if (nssCrl == NULL) { goto cleanup; } PKIX_CHECK(pkix_pl_CRL_CreateWithSignedCRL (nssCrl, &crl, plContext), PKIX_CRLCREATEWITHSIGNEDCRLFAILED); nssCrl = NULL; PKIX_CHECK(PKIX_List_AppendItem (crlList, (PKIX_PL_Object *) crl, plContext), PKIX_LISTAPPENDITEMFAILED); cleanup: if (nssCrl) { SEC_DestroyCrl(nssCrl); } 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 *derCrlItem = NULL; void *derBytes = NULL; PKIX_UInt32 derLength; PKIX_PL_CRL *crl = NULL; PKIX_ENTER(CRL, "PKIX_PL_CRL_Create"); PKIX_NULLCHECK_TWO(byteArray, pCrl); PKIX_CHECK(PKIX_PL_ByteArray_GetLength (byteArray, &derLength, plContext), PKIX_BYTEARRAYGETLENGTHFAILED); if (derLength == 0){ PKIX_ERROR(PKIX_ZEROLENGTHBYTEARRAYFORCRLENCODING); } PKIX_CHECK(PKIX_PL_ByteArray_GetPointer (byteArray, &derBytes, plContext), PKIX_BYTEARRAYGETPOINTERFAILED); PKIX_CRL_DEBUG("\t\tCalling SECITEM_AllocItem\n"); derCrlItem = SECITEM_AllocItem(NULL, NULL, derLength); if (derCrlItem == NULL){ PKIX_ERROR(PKIX_OUTOFMEMORY); } PKIX_CRL_DEBUG("\t\tCalling PORT_Memcpy\n"); (void) PORT_Memcpy(derCrlItem->data, derBytes, derLength); PKIX_CRL_DEBUG("\t\tCalling CERT_DecodeDERCrl\n"); nssSignedCrl = CERT_DecodeDERCrl(NULL, derCrlItem, SEC_CRL_TYPE); if (nssSignedCrl == NULL){ PKIX_ERROR(PKIX_CERTDECODEDERCRLFAILED); } PKIX_CHECK(pkix_pl_CRL_CreateWithSignedCRL (nssSignedCrl, &crl, plContext), PKIX_CRLCREATEWITHSIGNEDCRLFAILED); *pCrl = crl; cleanup: if (derCrlItem != NULL){ PKIX_CRL_DEBUG("\t\tCalling SECITEM_FreeItem\n"); SECITEM_FreeItem(derCrlItem, PKIX_TRUE); derCrlItem = NULL; } if (PKIX_ERROR_RECEIVED){ if (nssSignedCrl != NULL) { PKIX_CRL_DEBUG("\t\tCalling CERT_DestroyCrl\n"); CERT_DestroyCrl(nssSignedCrl); nssSignedCrl = NULL; } PKIX_DECREF(crl); } PKIX_FREE(derBytes); 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); /* 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); /* 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_GetCRLEntryForSerialNumber * (see comments in pkix_pl_pki.h) */ PKIX_Error * PKIX_PL_CRL_GetCRLEntryForSerialNumber( PKIX_PL_CRL *crl, PKIX_PL_BigInt *serialNumber, PKIX_PL_CRLEntry **pCRLEntry, void *plContext) { PKIX_PL_CRLEntry *crlEntry = NULL; PKIX_List *crlEntryList = NULL; PKIX_UInt32 numEntries = 0; PKIX_UInt32 i = 0; PKIX_Boolean cmpResult = PKIX_FALSE; PKIX_ENTER(CRL, "PKIX_PL_CRL_GetCRLEntryForSerialNumber"); PKIX_NULLCHECK_THREE(crl, serialNumber, pCRLEntry); /* Assume there is no entry for Serial Number at start */ *pCRLEntry = NULL; PKIX_CHECK(pkix_pl_CRL_GetCRLEntries(crl, &crlEntryList, plContext), PKIX_CRLGETCRLENTRIESFAILED); if (crlEntryList == NULL) { goto cleanup; } PKIX_CHECK(PKIX_List_GetLength(crlEntryList, &numEntries, plContext), PKIX_LISTGETLENGTHFAILED); for (i = 0; i < numEntries; i++){ PKIX_CHECK(PKIX_List_GetItem (crlEntryList, i, (PKIX_PL_Object **)&crlEntry, plContext), PKIX_LISTGETITEMFAILED); PKIX_CHECK(PKIX_PL_Object_Equals ((PKIX_PL_Object *)crlEntry->serialNumber, (PKIX_PL_Object *)serialNumber, &cmpResult, plContext), PKIX_OBJECTEQUALSFAILED); /* Found the entry for Serial Number */ if (cmpResult == PKIX_TRUE) { *pCRLEntry = crlEntry; goto cleanup; } PKIX_DECREF(crlEntry); } cleanup: PKIX_DECREF(crlEntryList); if (PKIX_ERROR_RECEIVED){ PKIX_DECREF(crlEntry); } 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); 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) { 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); }