blob: 6348b893651161320ec458a2ac25f9d4e8878056 [file] [log] [blame]
/* 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_tools.c
*
* Private Utility Functions
*
*/
#include "pkix_tools.h"
#define CACHE_ITEM_PERIOD_SECONDS (3600) /* one hour */
/*
* This cahce period is only for CertCache. A Cert from a trusted CertStore
* should be checked more frequently for update new arrival, etc.
*/
#define CACHE_TRUST_ITEM_PERIOD_SECONDS (CACHE_ITEM_PERIOD_SECONDS/10)
extern PKIX_PL_HashTable *cachedCertChainTable;
extern PKIX_PL_HashTable *cachedCertTable;
extern PKIX_PL_HashTable *cachedCrlEntryTable;
/* Following variables are used to checked cache hits - can be taken out */
extern int pkix_ccAddCount;
extern int pkix_ccLookupCount;
extern int pkix_ccRemoveCount;
extern int pkix_cAddCount;
extern int pkix_cLookupCount;
extern int pkix_cRemoveCount;
extern int pkix_ceAddCount;
extern int pkix_ceLookupCount;
#ifdef PKIX_OBJECT_LEAK_TEST
/* Following variables are used for object leak test */
char *nonNullValue = "Non Empty Value";
PKIX_Boolean noErrorState = PKIX_TRUE;
PKIX_Boolean runningLeakTest;
PKIX_Boolean errorGenerated;
PKIX_UInt32 stackPosition;
PKIX_UInt32 *fnStackInvCountArr;
char **fnStackNameArr;
PLHashTable *fnInvTable;
PKIX_UInt32 testStartFnStackPosition;
char *errorFnStackString;
#endif /* PKIX_OBJECT_LEAK_TEST */
/* --Private-Functions-------------------------------------------- */
#ifdef PKIX_OBJECT_LEAK_TEST
/*
* FUNCTION: pkix_ErrorGen_Hash
* DESCRIPTION:
*
* Hash function to be used in object leak test hash table.
*
*/
PLHashNumber PR_CALLBACK
pkix_ErrorGen_Hash (const void *key)
{
char *str = NULL;
PLHashNumber rv = (*(PRUint8*)key) << 5;
PRUint32 i, counter = 0;
PRUint8 *rvc = (PRUint8 *)&rv;
while ((str = fnStackNameArr[counter++]) != NULL) {
PRUint32 len = strlen(str);
for( i = 0; i < len; i++ ) {
rvc[ i % sizeof(rv) ] ^= *str;
str++;
}
}
return rv;
}
#endif /* PKIX_OBJECT_LEAK_TEST */
/*
* FUNCTION: pkix_IsCertSelfIssued
* DESCRIPTION:
*
* Checks whether the Cert pointed to by "cert" is self-issued and stores the
* Boolean result at "pSelfIssued". A Cert is considered self-issued if the
* Cert's issuer matches the Cert's subject. If the subject or issuer is
* not specified, a PKIX_FALSE is returned.
*
* PARAMETERS:
* "cert"
* Address of Cert used to determine whether Cert is self-issued.
* Must be non-NULL.
* "pSelfIssued"
* Address where Boolean 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 Cert 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_IsCertSelfIssued(
PKIX_PL_Cert *cert,
PKIX_Boolean *pSelfIssued,
void *plContext)
{
PKIX_PL_X500Name *subject = NULL;
PKIX_PL_X500Name *issuer = NULL;
PKIX_ENTER(CERT, "pkix_IsCertSelfIssued");
PKIX_NULLCHECK_TWO(cert, pSelfIssued);
PKIX_CHECK(PKIX_PL_Cert_GetSubject(cert, &subject, plContext),
PKIX_CERTGETSUBJECTFAILED);
PKIX_CHECK(PKIX_PL_Cert_GetIssuer(cert, &issuer, plContext),
PKIX_CERTGETISSUERFAILED);
if (subject == NULL || issuer == NULL) {
*pSelfIssued = PKIX_FALSE;
} else {
PKIX_CHECK(PKIX_PL_X500Name_Match
(subject, issuer, pSelfIssued, plContext),
PKIX_X500NAMEMATCHFAILED);
}
cleanup:
PKIX_DECREF(subject);
PKIX_DECREF(issuer);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_Throw
* DESCRIPTION:
*
* Creates an Error using the value of "errorCode", the character array
* pointed to by "funcName", the character array pointed to by "errorText",
* and the Error pointed to by "cause" (if any), and stores it at "pError".
*
* If "cause" is not NULL and has an errorCode of "PKIX_FATAL_ERROR",
* then there is no point creating a new Error object. Rather, we simply
* store "cause" at "pError".
*
* PARAMETERS:
* "errorCode"
* Value of error code.
* "funcName"
* Address of EscASCII array representing name of function throwing error.
* Must be non-NULL.
* "errnum"
* PKIX_ERRMSGNUM of error description for new error.
* "cause"
* Address of Error representing error's cause.
* "pError"
* 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 an Error 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_Throw(
PKIX_ERRORCLASS errorClass,
const char *funcName,
PKIX_ERRORCODE errorCode,
PKIX_ERRORCLASS overrideClass,
PKIX_Error *cause,
PKIX_Error **pError,
void *plContext)
{
PKIX_Error *error = NULL;
PKIX_ENTER(ERROR, "pkix_Throw");
PKIX_NULLCHECK_TWO(funcName, pError);
*pError = NULL;
#ifdef PKIX_OBJECT_LEAK_TEST
noErrorState = PKIX_TRUE;
if (pkixLog) {
#ifdef PKIX_ERROR_DESCRIPTION
PR_LOG(pkixLog, 4, ("Error in function \"%s\":\"%s\" with cause \"%s\"\n",
funcName, PKIX_ErrorText[errorCode],
(cause ? PKIX_ErrorText[cause->errCode] : "null")));
#else
PR_LOG(pkixLog, 4, ("Error in function \"%s\": error code \"%d\"\n",
funcName, errorCode));
#endif /* PKIX_ERROR_DESCRIPTION */
PORT_Assert(strcmp(funcName, "PKIX_PL_Object_DecRef"));
}
#endif /* PKIX_OBJECT_LEAK_TEST */
/* if cause has error class of PKIX_FATAL_ERROR, return immediately */
if (cause) {
if (cause->errClass == PKIX_FATAL_ERROR){
PKIX_INCREF(cause);
*pError = cause;
goto cleanup;
}
}
if (overrideClass == PKIX_FATAL_ERROR){
errorClass = overrideClass;
}
pkixTempResult = PKIX_Error_Create(errorClass, cause, NULL,
errorCode, &error, plContext);
if (!pkixTempResult) {
/* Setting plErr error code:
* get it from PORT_GetError if it is a leaf error and
* default error code does not exist(eq 0) */
if (!cause && !error->plErr) {
error->plErr = PKIX_PL_GetPLErrorCode();
}
}
*pError = error;
cleanup:
PKIX_DEBUG_EXIT(ERROR);
pkixErrorClass = 0;
#ifdef PKIX_OBJECT_LEAK_TEST
noErrorState = PKIX_FALSE;
if (runningLeakTest && fnStackNameArr) {
PR_LOG(pkixLog, 5,
("%s%*s<- %s(%d) - %s\n", (errorGenerated ? "*" : " "),
stackPosition, " ", fnStackNameArr[stackPosition],
stackPosition, myFuncName));
fnStackNameArr[stackPosition--] = NULL;
}
#endif /* PKIX_OBJECT_LEAK_TEST */
return (pkixTempResult);
}
/*
* FUNCTION: pkix_CheckTypes
* DESCRIPTION:
*
* Checks that the types of the Object pointed to by "first" and the Object
* pointed to by "second" are both equal to the value of "type". If they
* are not equal, a PKIX_Error is returned.
*
* PARAMETERS:
* "first"
* Address of first Object. Must be non-NULL.
* "second"
* Address of second Object. Must be non-NULL.
* "type"
* Value of type to check against.
* "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 an Error 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_CheckTypes(
PKIX_PL_Object *first,
PKIX_PL_Object *second,
PKIX_UInt32 type,
void *plContext)
{
PKIX_UInt32 firstType, secondType;
PKIX_ENTER(OBJECT, "pkix_CheckTypes");
PKIX_NULLCHECK_TWO(first, second);
PKIX_CHECK(PKIX_PL_Object_GetType(first, &firstType, plContext),
PKIX_COULDNOTGETFIRSTOBJECTTYPE);
PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext),
PKIX_COULDNOTGETSECONDOBJECTTYPE);
if ((firstType != type)||(firstType != secondType)) {
PKIX_ERROR(PKIX_OBJECTTYPESDONOTMATCH);
}
cleanup:
PKIX_RETURN(OBJECT);
}
/*
* FUNCTION: pkix_CheckType
* DESCRIPTION:
*
* Checks that the type of the Object pointed to by "object" is equal to the
* value of "type". If it is not equal, a PKIX_Error is returned.
*
* PARAMETERS:
* "object"
* Address of Object. Must be non-NULL.
* "type"
* Value of type to check against.
* "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 an Error 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_CheckType(
PKIX_PL_Object *object,
PKIX_UInt32 type,
void *plContext)
{
return (pkix_CheckTypes(object, object, type, plContext));
}
/*
* FUNCTION: pkix_hash
* DESCRIPTION:
*
* Computes a hash value for "length" bytes starting at the array of bytes
* pointed to by "bytes" and stores the result at "pHash".
*
* XXX To speed this up, we could probably read 32 bits at a time from
* bytes (maybe even 64 bits on some platforms)
*
* PARAMETERS:
* "bytes"
* Address of array of bytes to hash. Must be non-NULL.
* "length"
* Number of bytes to hash.
* "pHash"
* 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 Fatal Error if the function fails in an unrecoverable way.
*/
PKIX_Error *
pkix_hash(
const unsigned char *bytes,
PKIX_UInt32 length,
PKIX_UInt32 *pHash,
void *plContext)
{
PKIX_UInt32 i;
PKIX_UInt32 hash;
PKIX_ENTER(OBJECT, "pkix_hash");
if (length != 0) {
PKIX_NULLCHECK_ONE(bytes);
}
PKIX_NULLCHECK_ONE(pHash);
hash = 0;
for (i = 0; i < length; i++) {
/* hash = 31 * hash + bytes[i]; */
hash = (hash << 5) - hash + bytes[i];
}
*pHash = hash;
PKIX_RETURN(OBJECT);
}
/*
* FUNCTION: pkix_countArray
* DESCRIPTION:
*
* Counts the number of elements in the null-terminated array of pointers
* pointed to by "array" and returns the result.
*
* PARAMETERS
* "array"
* Address of null-terminated array of pointers.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* Returns the number of elements in the array.
*/
PKIX_UInt32
pkix_countArray(void **array)
{
PKIX_UInt32 count = 0;
if (array) {
while (*array++) {
count++;
}
}
return (count);
}
/*
* FUNCTION: pkix_duplicateImmutable
* DESCRIPTION:
*
* Convenience callback function used for duplicating immutable objects.
* Since the objects can not be modified, this function simply increments the
* reference count on the object, and returns a reference to that object.
*
* (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h)
*/
PKIX_Error *
pkix_duplicateImmutable(
PKIX_PL_Object *object,
PKIX_PL_Object **pNewObject,
void *plContext)
{
PKIX_ENTER(OBJECT, "pkix_duplicateImmutable");
PKIX_NULLCHECK_TWO(object, pNewObject);
PKIX_INCREF(object);
*pNewObject = object;
cleanup:
PKIX_RETURN(OBJECT);
}
/* --String-Encoding-Conversion-Functions------------------------ */
/*
* FUNCTION: pkix_hex2i
* DESCRIPTION:
*
* Converts hexadecimal character "c" to its integer value and returns result.
*
* PARAMETERS
* "c"
* Character to convert to a hex value.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* The hexadecimal value of "c". Otherwise -1. (Unsigned 0xFFFFFFFF).
*/
PKIX_UInt32
pkix_hex2i(char c)
{
if ((c >= '0')&&(c <= '9'))
return (c-'0');
else if ((c >= 'a')&&(c <= 'f'))
return (c-'a'+10);
else if ((c >= 'A')&&(c <= 'F'))
return (c-'A'+10);
else
return ((PKIX_UInt32)(-1));
}
/*
* FUNCTION: pkix_i2hex
* DESCRIPTION:
*
* Converts integer value "digit" to its ASCII hex value
*
* PARAMETERS
* "digit"
* Value of integer to convert to ASCII hex value. Must be 0-15.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* The ASCII hexadecimal value of "digit".
*/
char
pkix_i2hex(char digit)
{
if ((digit >= 0)&&(digit <= 9))
return (digit+'0');
else if ((digit >= 0xa)&&(digit <= 0xf))
return (digit - 10 + 'a');
else
return (-1);
}
/*
* FUNCTION: pkix_isPlaintext
* DESCRIPTION:
*
* Returns whether character "c" is plaintext using EscASCII or EscASCII_Debug
* depending on the value of "debug".
*
* In EscASCII, [01, 7E] except '&' are plaintext.
* In EscASCII_Debug [20, 7E] except '&' are plaintext.
*
* PARAMETERS:
* "c"
* Character to check.
* "debug"
* Value of debug flag.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* True if "c" is plaintext.
*/
PKIX_Boolean
pkix_isPlaintext(unsigned char c, PKIX_Boolean debug) {
return ((c >= 0x01)&&(c <= 0x7E)&&(c != '&')&&(!debug || (c >= 20)));
}
/* --Cache-Functions------------------------ */
/*
* FUNCTION: pkix_CacheCertChain_Lookup
* DESCRIPTION:
*
* Look up CertChain Hash Table for a cached BuildResult based on "targetCert"
* and "anchors" as the hash keys. If there is no item to match the key,
* PKIX_FALSE is stored at "pFound". If an item is found, its cache time is
* compared to "testDate". If expired, the item is removed and PKIX_FALSE is
* stored at "pFound". Otherwise, PKIX_TRUE is stored at "pFound" and the
* BuildResult is stored at "pBuildResult".
* The hashtable is maintained in the following ways:
* 1) When creating the hashtable, maximum bucket size can be specified (0 for
* unlimited). If items in a bucket reaches its full size, an new addition
* will trigger the removal of the old as FIFO sequence.
* 2) A PKIX_PL_Date created with current time offset by constant
* CACHE_ITEM_PERIOD_SECONDS is attached to each item in the Hash Table.
* When an item is retrieved, this date is compared against "testDate" for
* validity. If comparison indicates this item is expired, the item is
* removed from the bucket.
*
* PARAMETERS:
* "targetCert"
* Address of Target Cert as key to retrieve this CertChain. Must be
* non-NULL.
* "anchors"
* Address of PKIX_List of "anchors" is used as key to retrive CertChain.
* Must be non-NULL.
* "testDate"
* Address of PKIX_PL_Date for verifying time validity and cache validity.
* May be NULL. If testDate is NULL, this cache item will not be out-dated.
* "pFound"
* Address of PKIX_Boolean indicating valid data is found.
* Must be non-NULL.
* "pBuildResult"
* Address where BuildResult 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 an Error 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_CacheCertChain_Lookup(
PKIX_PL_Cert* targetCert,
PKIX_List* anchors,
PKIX_PL_Date *testDate,
PKIX_Boolean *pFound,
PKIX_BuildResult **pBuildResult,
void *plContext)
{
PKIX_List *cachedValues = NULL;
PKIX_List *cachedKeys = NULL;
PKIX_Error *cachedCertChainError = NULL;
PKIX_PL_Date *cacheValidUntilDate = NULL;
PKIX_PL_Date *validityDate = NULL;
PKIX_Int32 cmpValidTimeResult = 0;
PKIX_Int32 cmpCacheTimeResult = 0;
PKIX_ENTER(BUILD, "pkix_CacheCertChain_Lookup");
PKIX_NULLCHECK_FOUR(targetCert, anchors, pFound, pBuildResult);
*pFound = PKIX_FALSE;
/* use trust anchors and target cert as hash key */
PKIX_CHECK(PKIX_List_Create(&cachedKeys, plContext),
PKIX_LISTCREATEFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys,
(PKIX_PL_Object *)targetCert,
plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys,
(PKIX_PL_Object *)anchors,
plContext),
PKIX_LISTAPPENDITEMFAILED);
cachedCertChainError = PKIX_PL_HashTable_Lookup
(cachedCertChainTable,
(PKIX_PL_Object *) cachedKeys,
(PKIX_PL_Object **) &cachedValues,
plContext);
pkix_ccLookupCount++;
/* retrieve data from hashed value list */
if (cachedValues != NULL && cachedCertChainError == NULL) {
PKIX_CHECK(PKIX_List_GetItem
(cachedValues,
0,
(PKIX_PL_Object **) &cacheValidUntilDate,
plContext),
PKIX_LISTGETITEMFAILED);
/* check validity time and cache age time */
PKIX_CHECK(PKIX_List_GetItem
(cachedValues,
1,
(PKIX_PL_Object **) &validityDate,
plContext),
PKIX_LISTGETITEMFAILED);
/* if testDate is not set, this cache item is not out-dated */
if (testDate) {
PKIX_CHECK(PKIX_PL_Object_Compare
((PKIX_PL_Object *)testDate,
(PKIX_PL_Object *)cacheValidUntilDate,
&cmpCacheTimeResult,
plContext),
PKIX_OBJECTCOMPARATORFAILED);
PKIX_CHECK(PKIX_PL_Object_Compare
((PKIX_PL_Object *)testDate,
(PKIX_PL_Object *)validityDate,
&cmpValidTimeResult,
plContext),
PKIX_OBJECTCOMPARATORFAILED);
}
/* certs' date are all valid and cache item is not old */
if (cmpValidTimeResult <= 0 && cmpCacheTimeResult <=0) {
PKIX_CHECK(PKIX_List_GetItem
(cachedValues,
2,
(PKIX_PL_Object **) pBuildResult,
plContext),
PKIX_LISTGETITEMFAILED);
*pFound = PKIX_TRUE;
} else {
pkix_ccRemoveCount++;
*pFound = PKIX_FALSE;
/* out-dated item, remove it from cache */
PKIX_CHECK(PKIX_PL_HashTable_Remove
(cachedCertChainTable,
(PKIX_PL_Object *) cachedKeys,
plContext),
PKIX_HASHTABLEREMOVEFAILED);
}
}
cleanup:
PKIX_DECREF(cachedValues);
PKIX_DECREF(cachedKeys);
PKIX_DECREF(cachedCertChainError);
PKIX_DECREF(cacheValidUntilDate);
PKIX_DECREF(validityDate);
PKIX_RETURN(BUILD);
}
/*
* FUNCTION: pkix_CacheCertChain_Remove
* DESCRIPTION:
*
* Remove CertChain Hash Table entry based on "targetCert" and "anchors"
* as the hash keys. If there is no item to match the key, no action is
* taken.
* The hashtable is maintained in the following ways:
* 1) When creating the hashtable, maximum bucket size can be specified (0 for
* unlimited). If items in a bucket reaches its full size, an new addition
* will trigger the removal of the old as FIFO sequence.
* 2) A PKIX_PL_Date created with current time offset by constant
* CACHE_ITEM_PERIOD_SECONDS is attached to each item in the Hash Table.
* When an item is retrieved, this date is compared against "testDate" for
* validity. If comparison indicates this item is expired, the item is
* removed from the bucket.
*
* PARAMETERS:
* "targetCert"
* Address of Target Cert as key to retrieve this CertChain. Must be
* non-NULL.
* "anchors"
* Address of PKIX_List of "anchors" is used as key to retrive CertChain.
* 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 an Error 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_CacheCertChain_Remove(
PKIX_PL_Cert* targetCert,
PKIX_List* anchors,
void *plContext)
{
PKIX_List *cachedKeys = NULL;
PKIX_ENTER(BUILD, "pkix_CacheCertChain_Remove");
PKIX_NULLCHECK_TWO(targetCert, anchors);
/* use trust anchors and target cert as hash key */
PKIX_CHECK(PKIX_List_Create(&cachedKeys, plContext),
PKIX_LISTCREATEFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys,
(PKIX_PL_Object *)targetCert,
plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys,
(PKIX_PL_Object *)anchors,
plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK_ONLY_FATAL(PKIX_PL_HashTable_Remove
(cachedCertChainTable,
(PKIX_PL_Object *) cachedKeys,
plContext),
PKIX_HASHTABLEREMOVEFAILED);
pkix_ccRemoveCount++;
cleanup:
PKIX_DECREF(cachedKeys);
PKIX_RETURN(BUILD);
}
/*
* FUNCTION: pkix_CacheCertChain_Add
* DESCRIPTION:
*
* Add a BuildResult to the CertChain Hash Table for a "buildResult" with
* "targetCert" and "anchors" as the hash keys.
* "validityDate" is the most restricted notAfter date of all Certs in
* this CertChain and is verified when this BuildChain is retrieved.
* The hashtable is maintained in the following ways:
* 1) When creating the hashtable, maximum bucket size can be specified (0 for
* unlimited). If items in a bucket reaches its full size, an new addition
* will trigger the removal of the old as FIFO sequence.
* 2) A PKIX_PL_Date created with current time offset by constant
* CACHE_ITEM_PERIOD_SECONDS is attached to each item in the Hash Table.
* When an item is retrieved, this date is compared against "testDate" for
* validity. If comparison indicates this item is expired, the item is
* removed from the bucket.
*
* PARAMETERS:
* "targetCert"
* Address of Target Cert as key to retrieve this CertChain. Must be
* non-NULL.
* "anchors"
* Address of PKIX_List of "anchors" is used as key to retrive CertChain.
* Must be non-NULL.
* "validityDate"
* Address of PKIX_PL_Date contains the most restriced notAfter time of
* all "certs". Must be non-NULL.
* Address of PKIX_Boolean indicating valid data is found.
* Must be non-NULL.
* "buildResult"
* Address of BuildResult to be cached. 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 an Error 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_CacheCertChain_Add(
PKIX_PL_Cert* targetCert,
PKIX_List* anchors,
PKIX_PL_Date *validityDate,
PKIX_BuildResult *buildResult,
void *plContext)
{
PKIX_List *cachedValues = NULL;
PKIX_List *cachedKeys = NULL;
PKIX_Error *cachedCertChainError = NULL;
PKIX_PL_Date *cacheValidUntilDate = NULL;
PKIX_ENTER(BUILD, "pkix_CacheCertChain_Add");
PKIX_NULLCHECK_FOUR(targetCert, anchors, validityDate, buildResult);
PKIX_CHECK(PKIX_List_Create(&cachedKeys, plContext),
PKIX_LISTCREATEFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys, (PKIX_PL_Object *)targetCert, plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys, (PKIX_PL_Object *)anchors, plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK(PKIX_List_Create(&cachedValues, plContext),
PKIX_LISTCREATEFAILED);
PKIX_CHECK(PKIX_PL_Date_Create_CurrentOffBySeconds
(CACHE_ITEM_PERIOD_SECONDS,
&cacheValidUntilDate,
plContext),
PKIX_DATECREATECURRENTOFFBYSECONDSFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedValues,
(PKIX_PL_Object *)cacheValidUntilDate,
plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedValues, (PKIX_PL_Object *)validityDate, plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedValues, (PKIX_PL_Object *)buildResult, plContext),
PKIX_LISTAPPENDITEMFAILED);
cachedCertChainError = PKIX_PL_HashTable_Add
(cachedCertChainTable,
(PKIX_PL_Object *) cachedKeys,
(PKIX_PL_Object *) cachedValues,
plContext);
pkix_ccAddCount++;
if (cachedCertChainError != NULL) {
PKIX_DEBUG("PKIX_PL_HashTable_Add for CertChain skipped: "
"entry existed\n");
}
cleanup:
PKIX_DECREF(cachedValues);
PKIX_DECREF(cachedKeys);
PKIX_DECREF(cachedCertChainError);
PKIX_DECREF(cacheValidUntilDate);
PKIX_RETURN(BUILD);
}
/*
* FUNCTION: pkix_CacheCert_Lookup
* DESCRIPTION:
*
* Look up Cert Hash Table for a cached item based on "store" and Subject in
* "certSelParams" as the hash keys and returns values Certs in "pCerts".
* If there isn't an item to match the key, a PKIX_FALSE is returned at
* "pFound". The item's cache time is verified with "testDate". If out-dated,
* this item is removed and PKIX_FALSE is returned at "pFound".
* This hashtable is maintained in the following ways:
* 1) When creating the hashtable, maximum bucket size can be specified (0 for
* unlimited). If items in a bucket reaches its full size, an new addition
* will trigger the removal of the old as FIFO sequence.
* 2) A PKIX_PL_Date created with current time offset by constant
* CACHE_ITEM_PERIOD_SECONDS is attached to each item in the Hash Table.
* If the CertStore this Cert is from is a trusted one, the cache period is
* shorter so cache can be updated more frequently.
* When an item is retrieved, this date is compared against "testDate" for
* validity. If comparison indicates this item is expired, the item is
* removed from the bucket.
*
* PARAMETERS:
* "store"
* Address of CertStore as key to retrieve this CertChain. Must be
* non-NULL.
* "certSelParams"
* Address of ComCertSelParams that its subject is used as key to retrieve
* this CertChain. Must be non-NULL.
* "testDate"
* Address of PKIX_PL_Date for verifying time cache validity.
* Must be non-NULL. If testDate is NULL, this cache item won't be out
* dated.
* "pFound"
* Address of KPKIX_Boolean indicating valid data is found.
* Must be non-NULL.
* "pCerts"
* Address PKIX_List where the CertChain will be stored. Must be no-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 an Error 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_CacheCert_Lookup(
PKIX_CertStore *store,
PKIX_ComCertSelParams *certSelParams,
PKIX_PL_Date *testDate,
PKIX_Boolean *pFound,
PKIX_List** pCerts,
void *plContext)
{
PKIX_PL_Cert *cert = NULL;
PKIX_List *cachedKeys = NULL;
PKIX_List *cachedValues = NULL;
PKIX_List *cachedCertList = NULL;
PKIX_List *selCertList = NULL;
PKIX_PL_X500Name *subject = NULL;
PKIX_PL_Date *invalidAfterDate = NULL;
PKIX_PL_Date *cacheValidUntilDate = NULL;
PKIX_CertSelector *certSel = NULL;
PKIX_Error *cachedCertError = NULL;
PKIX_Error *selectorError = NULL;
PKIX_CertSelector_MatchCallback selectorMatch = NULL;
PKIX_Int32 cmpValidTimeResult = PKIX_FALSE;
PKIX_Int32 cmpCacheTimeResult = 0;
PKIX_UInt32 numItems = 0;
PKIX_UInt32 i;
PKIX_ENTER(BUILD, "pkix_CacheCert_Lookup");
PKIX_NULLCHECK_TWO(store, certSelParams);
PKIX_NULLCHECK_TWO(pFound, pCerts);
*pFound = PKIX_FALSE;
PKIX_CHECK(PKIX_List_Create(&cachedKeys, plContext),
PKIX_LISTCREATEFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys, (PKIX_PL_Object *)store, plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK(PKIX_ComCertSelParams_GetSubject
(certSelParams, &subject, plContext),
PKIX_COMCERTSELPARAMSGETSUBJECTFAILED);
PKIX_NULLCHECK_ONE(subject);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys, (PKIX_PL_Object *)subject, plContext),
PKIX_LISTAPPENDITEMFAILED);
cachedCertError = PKIX_PL_HashTable_Lookup
(cachedCertTable,
(PKIX_PL_Object *) cachedKeys,
(PKIX_PL_Object **) &cachedValues,
plContext);
pkix_cLookupCount++;
if (cachedValues != NULL && cachedCertError == NULL) {
PKIX_CHECK(PKIX_List_GetItem
(cachedValues,
0,
(PKIX_PL_Object **) &cacheValidUntilDate,
plContext),
PKIX_LISTGETITEMFAILED);
if (testDate) {
PKIX_CHECK(PKIX_PL_Object_Compare
((PKIX_PL_Object *)testDate,
(PKIX_PL_Object *)cacheValidUntilDate,
&cmpCacheTimeResult,
plContext),
PKIX_OBJECTCOMPARATORFAILED);
}
if (cmpCacheTimeResult <= 0) {
PKIX_CHECK(PKIX_List_GetItem
(cachedValues,
1,
(PKIX_PL_Object **) &cachedCertList,
plContext),
PKIX_LISTGETITEMFAILED);
/*
* Certs put on cache satifies only for Subject,
* user selector and ComCertSelParams to filter.
*/
PKIX_CHECK(PKIX_CertSelector_Create
(NULL, NULL, &certSel, plContext),
PKIX_CERTSELECTORCREATEFAILED);
PKIX_CHECK(PKIX_CertSelector_SetCommonCertSelectorParams
(certSel, certSelParams, plContext),
PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED);
PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
(certSel, &selectorMatch, plContext),
PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);
PKIX_CHECK(PKIX_List_Create(&selCertList, plContext),
PKIX_LISTCREATEFAILED);
/*
* If any of the Cert on the list is out-dated, invalidate
* this cache item.
*/
PKIX_CHECK(PKIX_List_GetLength
(cachedCertList, &numItems, plContext),
PKIX_LISTGETLENGTHFAILED);
for (i = 0; i < numItems; i++){
PKIX_CHECK(PKIX_List_GetItem
(cachedCertList,
i,
(PKIX_PL_Object **)&cert,
plContext),
PKIX_LISTGETITEMFAILED);
PKIX_CHECK(PKIX_PL_Cert_GetValidityNotAfter
(cert, &invalidAfterDate, plContext),
PKIX_CERTGETVALIDITYNOTAFTERFAILED);
if (testDate) {
PKIX_CHECK(PKIX_PL_Object_Compare
((PKIX_PL_Object *)invalidAfterDate,
(PKIX_PL_Object *)testDate,
&cmpValidTimeResult,
plContext),
PKIX_OBJECTCOMPARATORFAILED);
}
if (cmpValidTimeResult < 0) {
pkix_cRemoveCount++;
*pFound = PKIX_FALSE;
/* one cert is out-dated, remove item from cache */
PKIX_CHECK(PKIX_PL_HashTable_Remove
(cachedCertTable,
(PKIX_PL_Object *) cachedKeys,
plContext),
PKIX_HASHTABLEREMOVEFAILED);
goto cleanup;
}
selectorError = selectorMatch(certSel, cert, plContext);
if (!selectorError){
/* put on the return list */
PKIX_CHECK(PKIX_List_AppendItem
(selCertList,
(PKIX_PL_Object *)cert,
plContext),
PKIX_LISTAPPENDITEMFAILED);
} else {
PKIX_DECREF(selectorError);
}
PKIX_DECREF(cert);
PKIX_DECREF(invalidAfterDate);
}
if (*pFound) {
PKIX_INCREF(selCertList);
*pCerts = selCertList;
}
} else {
pkix_cRemoveCount++;
*pFound = PKIX_FALSE;
/* cache item is out-dated, remove it from cache */
PKIX_CHECK(PKIX_PL_HashTable_Remove
(cachedCertTable,
(PKIX_PL_Object *) cachedKeys,
plContext),
PKIX_HASHTABLEREMOVEFAILED);
}
}
cleanup:
PKIX_DECREF(subject);
PKIX_DECREF(certSel);
PKIX_DECREF(cachedKeys);
PKIX_DECREF(cachedValues);
PKIX_DECREF(cacheValidUntilDate);
PKIX_DECREF(cert);
PKIX_DECREF(cachedCertList);
PKIX_DECREF(selCertList);
PKIX_DECREF(invalidAfterDate);
PKIX_DECREF(cachedCertError);
PKIX_DECREF(selectorError);
PKIX_RETURN(BUILD);
}
/*
* FUNCTION: pkix_CacheCert_Add
* DESCRIPTION:
*
* Add Cert Hash Table for a cached item based on "store" and Subject in
* "certSelParams" as the hash keys and have "certs" as the key value.
* This hashtable is maintained in the following ways:
* 1) When creating the hashtable, maximum bucket size can be specified (0 for
* unlimited). If items in a bucket reaches its full size, an new addition
* will trigger the removal of the old as FIFO sequence.
* 2) A PKIX_PL_Date created with current time offset by constant
* CACHE_ITEM_PERIOD_SECONDS is attached to each item in the Hash Table.
* If the CertStore this Cert is from is a trusted one, the cache period is
* shorter so cache can be updated more frequently.
* When an item is retrieved, this date is compared against "testDate" for
* validity. If comparison indicates this item is expired, the item is
* removed from the bucket.
*
* PARAMETERS:
* "store"
* Address of CertStore as key to retrieve this CertChain. Must be
* non-NULL.
* "certSelParams"
* Address of ComCertSelParams that its subject is used as key to retrieve
* this CertChain. Must be non-NULL.
* "certs"
* Address PKIX_List of Certs will be stored. Must be no-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 an Error 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_CacheCert_Add(
PKIX_CertStore *store,
PKIX_ComCertSelParams *certSelParams,
PKIX_List* certs,
void *plContext)
{
PKIX_List *cachedKeys = NULL;
PKIX_List *cachedValues = NULL;
PKIX_PL_Date *cacheValidUntilDate = NULL;
PKIX_PL_X500Name *subject = NULL;
PKIX_Error *cachedCertError = NULL;
PKIX_CertStore_CheckTrustCallback trustCallback = NULL;
PKIX_UInt32 cachePeriod = CACHE_ITEM_PERIOD_SECONDS;
PKIX_UInt32 numCerts = 0;
PKIX_ENTER(BUILD, "pkix_CacheCert_Add");
PKIX_NULLCHECK_THREE(store, certSelParams, certs);
PKIX_CHECK(PKIX_List_GetLength(certs, &numCerts,
plContext),
PKIX_LISTGETLENGTHFAILED);
if (numCerts == 0) {
/* Don't want to add an empty list. */
goto cleanup;
}
PKIX_CHECK(PKIX_List_Create(&cachedKeys, plContext),
PKIX_LISTCREATEFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys, (PKIX_PL_Object *)store, plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK(PKIX_ComCertSelParams_GetSubject
(certSelParams, &subject, plContext),
PKIX_COMCERTSELPARAMSGETSUBJECTFAILED);
PKIX_NULLCHECK_ONE(subject);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys, (PKIX_PL_Object *)subject, plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK(PKIX_List_Create(&cachedValues, plContext),
PKIX_LISTCREATEFAILED);
PKIX_CHECK(PKIX_CertStore_GetTrustCallback
(store, &trustCallback, plContext),
PKIX_CERTSTOREGETTRUSTCALLBACKFAILED);
if (trustCallback) {
cachePeriod = CACHE_TRUST_ITEM_PERIOD_SECONDS;
}
PKIX_CHECK(PKIX_PL_Date_Create_CurrentOffBySeconds
(cachePeriod, &cacheValidUntilDate, plContext),
PKIX_DATECREATECURRENTOFFBYSECONDSFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedValues,
(PKIX_PL_Object *)cacheValidUntilDate,
plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedValues,
(PKIX_PL_Object *)certs,
plContext),
PKIX_LISTAPPENDITEMFAILED);
cachedCertError = PKIX_PL_HashTable_Add
(cachedCertTable,
(PKIX_PL_Object *) cachedKeys,
(PKIX_PL_Object *) cachedValues,
plContext);
pkix_cAddCount++;
if (cachedCertError != NULL) {
PKIX_DEBUG("PKIX_PL_HashTable_Add for Certs skipped: "
"entry existed\n");
}
cleanup:
PKIX_DECREF(subject);
PKIX_DECREF(cachedKeys);
PKIX_DECREF(cachedValues);
PKIX_DECREF(cacheValidUntilDate);
PKIX_DECREF(cachedCertError);
PKIX_RETURN(BUILD);
}
/*
* FUNCTION: pkix_CacheCrlEntry_Lookup
* DESCRIPTION:
*
* Look up CrlEntry Hash Table for a cached item based on "store",
* "certIssuer" and "certSerialNumber" as the hash keys and returns values
* "pCrls". If there isn't an item to match the key, a PKIX_FALSE is
* returned at "pFound".
* This hashtable is maintained in the following way:
* 1) When creating the hashtable, maximum bucket size can be specified (0 for
* unlimited). If items in a bucket reaches its full size, an new addition
* will trigger the removal of the old as FIFO sequence.
*
* PARAMETERS:
* "store"
* Address of CertStore as key to retrieve this CertChain. Must be
* non-NULL.
* "certIssuer"
* Address of X500Name that is used as key to retrieve the CRLEntries.
* Must be non-NULL.
* "certSerialNumber"
* Address of BigInt that is used as key to retrieve the CRLEntries.
* Must be non-NULL.
* "pFound"
* Address of KPKIX_Boolean indicating valid data is found.
* Must be non-NULL.
* "pCrls"
* Address PKIX_List where the CRLEntry will be stored. Must be no-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 an Error 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_CacheCrlEntry_Lookup(
PKIX_CertStore *store,
PKIX_PL_X500Name *certIssuer,
PKIX_PL_BigInt *certSerialNumber,
PKIX_Boolean *pFound,
PKIX_List** pCrls,
void *plContext)
{
PKIX_List *cachedKeys = NULL;
PKIX_List *cachedCrlEntryList = NULL;
PKIX_Error *cachedCrlEntryError = NULL;
PKIX_ENTER(BUILD, "pkix_CacheCrlEntry_Lookup");
PKIX_NULLCHECK_THREE(store, certIssuer, certSerialNumber);
PKIX_NULLCHECK_TWO(pFound, pCrls);
*pFound = PKIX_FALSE;
/* Find CrlEntry(s) by issuer and serial number */
PKIX_CHECK(PKIX_List_Create(&cachedKeys, plContext),
PKIX_LISTCREATEFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys, (PKIX_PL_Object *)store, plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys, (PKIX_PL_Object *)certIssuer, plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys,
(PKIX_PL_Object *)certSerialNumber,
plContext),
PKIX_LISTAPPENDITEMFAILED);
cachedCrlEntryError = PKIX_PL_HashTable_Lookup
(cachedCrlEntryTable,
(PKIX_PL_Object *) cachedKeys,
(PKIX_PL_Object **) &cachedCrlEntryList,
plContext);
pkix_ceLookupCount++;
/*
* We don't need check Date to invalidate this cache item,
* the item is uniquely defined and won't be reverted. Let
* the FIFO for cleaning up.
*/
if (cachedCrlEntryList != NULL && cachedCrlEntryError == NULL ) {
PKIX_INCREF(cachedCrlEntryList);
*pCrls = cachedCrlEntryList;
*pFound = PKIX_TRUE;
} else {
*pFound = PKIX_FALSE;
}
cleanup:
PKIX_DECREF(cachedKeys);
PKIX_DECREF(cachedCrlEntryList);
PKIX_DECREF(cachedCrlEntryError);
PKIX_RETURN(BUILD);
}
/*
* FUNCTION: pkix_CacheCrlEntry_Add
* DESCRIPTION:
*
* Look up CrlEntry Hash Table for a cached item based on "store",
* "certIssuer" and "certSerialNumber" as the hash keys and have "pCrls" as
* the hash value. If there isn't an item to match the key, a PKIX_FALSE is
* returned at "pFound".
* This hashtable is maintained in the following way:
* 1) When creating the hashtable, maximum bucket size can be specified (0 for
* unlimited). If items in a bucket reaches its full size, an new addition
* will trigger the removal of the old as FIFO sequence.
*
* PARAMETERS:
* "store"
* Address of CertStore as key to retrieve this CertChain. Must be
* non-NULL.
* "certIssuer"
* Address of X500Name that is used as key to retrieve the CRLEntries.
* Must be non-NULL.
* "certSerialNumber"
* Address of BigInt that is used as key to retrieve the CRLEntries.
* Must be non-NULL.
* "crls"
* Address PKIX_List where the CRLEntry is stored. Must be no-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 an Error 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_CacheCrlEntry_Add(
PKIX_CertStore *store,
PKIX_PL_X500Name *certIssuer,
PKIX_PL_BigInt *certSerialNumber,
PKIX_List* crls,
void *plContext)
{
PKIX_List *cachedKeys = NULL;
PKIX_Error *cachedCrlEntryError = NULL;
PKIX_ENTER(BUILD, "pkix_CacheCrlEntry_Add");
PKIX_NULLCHECK_THREE(store, certIssuer, certSerialNumber);
PKIX_NULLCHECK_ONE(crls);
/* Add CrlEntry(s) by issuer and serial number */
PKIX_CHECK(PKIX_List_Create(&cachedKeys, plContext),
PKIX_LISTCREATEFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys, (PKIX_PL_Object *)store, plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys, (PKIX_PL_Object *)certIssuer, plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(cachedKeys,
(PKIX_PL_Object *)certSerialNumber,
plContext),
PKIX_LISTAPPENDITEMFAILED);
cachedCrlEntryError = PKIX_PL_HashTable_Add
(cachedCrlEntryTable,
(PKIX_PL_Object *) cachedKeys,
(PKIX_PL_Object *) crls,
plContext);
pkix_ceAddCount++;
cleanup:
PKIX_DECREF(cachedKeys);
PKIX_DECREF(cachedCrlEntryError);
PKIX_RETURN(BUILD);
}
#ifdef PKIX_OBJECT_LEAK_TEST
/* TEST_START_FN and testStartFnStackPosition define at what state
* of the stack the object leak testing should begin. The condition
* in pkix_CheckForGeneratedError works the following way: do leak
* testing if at position testStartFnStackPosition in stack array
* (fnStackNameArr) we have called function TEST_START_FN.
* Note, that stack array get filled only when executing libpkix
* functions.
* */
#define TEST_START_FN "PKIX_BuildChain"
PKIX_Error*
pkix_CheckForGeneratedError(PKIX_StdVars * stdVars,
PKIX_ERRORCLASS errClass,
char * fnName,
PKIX_Boolean *errSetFlag,
void * plContext)
{
PKIX_Error *genErr = NULL;
PKIX_UInt32 pos = 0;
PKIX_UInt32 strLen = 0;
if (fnName) {
if (fnStackNameArr[testStartFnStackPosition] == NULL ||
strcmp(fnStackNameArr[testStartFnStackPosition], TEST_START_FN)
) {
/* return with out error if not with in boundary */
return NULL;
}
if (!strcmp(fnName, TEST_START_FN)) {
*errSetFlag = PKIX_TRUE;
noErrorState = PKIX_FALSE;
errorGenerated = PKIX_FALSE;
}
}
if (noErrorState || errorGenerated) return NULL;
if (fnName && (
!strcmp(fnName, "PKIX_PL_Object_DecRef") ||
!strcmp(fnName, "PKIX_PL_Object_Unlock") ||
!strcmp(fnName, "pkix_UnlockObject") ||
!strcmp(fnName, "pkix_Throw") ||
!strcmp(fnName, "pkix_trace_dump_cert") ||
!strcmp(fnName, "PKIX_PL_Free"))) {
/* do not generate error for this functions */
noErrorState = PKIX_TRUE;
*errSetFlag = PKIX_TRUE;
return NULL;
}
if (PL_HashTableLookup(fnInvTable, &fnStackInvCountArr[stackPosition - 1])) {
return NULL;
}
PL_HashTableAdd(fnInvTable, &fnStackInvCountArr[stackPosition - 1], nonNullValue);
errorGenerated = PKIX_TRUE;
noErrorState = PKIX_TRUE;
genErr = PKIX_DoThrow(stdVars, errClass, PKIX_MEMLEAKGENERATEDERROR,
errClass, plContext);
while(fnStackNameArr[pos]) {
strLen += PORT_Strlen(fnStackNameArr[pos++]) + 1;
}
strLen += 1; /* end of line. */
pos = 0;
errorFnStackString = PORT_ZAlloc(strLen);
while(fnStackNameArr[pos]) {
strcat(errorFnStackString, "/");
strcat(errorFnStackString, fnStackNameArr[pos++]);
}
noErrorState = PKIX_FALSE;
return genErr;
}
#endif /* PKIX_OBJECT_LEAK_TEST */