mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-08-11 05:29:00 +00:00
1069 lines
32 KiB
C
1069 lines
32 KiB
C
/* 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);
|
|
}
|