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