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