diff options
Diffstat (limited to 'security/nss/lib/libpkix/pkix/util/pkix_tools.c')
-rwxr-xr-x | security/nss/lib/libpkix/pkix/util/pkix_tools.c | 1525 |
1 files changed, 1525 insertions, 0 deletions
diff --git a/security/nss/lib/libpkix/pkix/util/pkix_tools.c b/security/nss/lib/libpkix/pkix/util/pkix_tools.c new file mode 100755 index 0000000000..4c01f8da14 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/util/pkix_tools.c @@ -0,0 +1,1525 @@ +/* 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); + *pFound = PKIX_TRUE; + } 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_List *cachedCerts = 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_DUPLICATE(certs, &cachedCerts, plContext, + PKIX_OBJECTDUPLICATELISTFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (cachedValues, + (PKIX_PL_Object *)cachedCerts, + 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(cachedCerts); + 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 */ |