1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/libpkix/pkix/util/pkix_tools.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1519 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +/* 1.8 + * pkix_tools.c 1.9 + * 1.10 + * Private Utility Functions 1.11 + * 1.12 + */ 1.13 + 1.14 +#include "pkix_tools.h" 1.15 + 1.16 +#define CACHE_ITEM_PERIOD_SECONDS (3600) /* one hour */ 1.17 + 1.18 +/* 1.19 + * This cahce period is only for CertCache. A Cert from a trusted CertStore 1.20 + * should be checked more frequently for update new arrival, etc. 1.21 + */ 1.22 +#define CACHE_TRUST_ITEM_PERIOD_SECONDS (CACHE_ITEM_PERIOD_SECONDS/10) 1.23 + 1.24 +extern PKIX_PL_HashTable *cachedCertChainTable; 1.25 +extern PKIX_PL_HashTable *cachedCertTable; 1.26 +extern PKIX_PL_HashTable *cachedCrlEntryTable; 1.27 + 1.28 +/* Following variables are used to checked cache hits - can be taken out */ 1.29 +extern int pkix_ccAddCount; 1.30 +extern int pkix_ccLookupCount; 1.31 +extern int pkix_ccRemoveCount; 1.32 +extern int pkix_cAddCount; 1.33 +extern int pkix_cLookupCount; 1.34 +extern int pkix_cRemoveCount; 1.35 +extern int pkix_ceAddCount; 1.36 +extern int pkix_ceLookupCount; 1.37 + 1.38 +#ifdef PKIX_OBJECT_LEAK_TEST 1.39 +/* Following variables are used for object leak test */ 1.40 +char *nonNullValue = "Non Empty Value"; 1.41 +PKIX_Boolean noErrorState = PKIX_TRUE; 1.42 +PKIX_Boolean runningLeakTest; 1.43 +PKIX_Boolean errorGenerated; 1.44 +PKIX_UInt32 stackPosition; 1.45 +PKIX_UInt32 *fnStackInvCountArr; 1.46 +char **fnStackNameArr; 1.47 +PLHashTable *fnInvTable; 1.48 +PKIX_UInt32 testStartFnStackPosition; 1.49 +char *errorFnStackString; 1.50 +#endif /* PKIX_OBJECT_LEAK_TEST */ 1.51 + 1.52 +/* --Private-Functions-------------------------------------------- */ 1.53 + 1.54 +#ifdef PKIX_OBJECT_LEAK_TEST 1.55 +/* 1.56 + * FUNCTION: pkix_ErrorGen_Hash 1.57 + * DESCRIPTION: 1.58 + * 1.59 + * Hash function to be used in object leak test hash table. 1.60 + * 1.61 + */ 1.62 +PLHashNumber PR_CALLBACK 1.63 +pkix_ErrorGen_Hash (const void *key) 1.64 +{ 1.65 + char *str = NULL; 1.66 + PLHashNumber rv = (*(PRUint8*)key) << 5; 1.67 + PRUint32 i, counter = 0; 1.68 + PRUint8 *rvc = (PRUint8 *)&rv; 1.69 + 1.70 + while ((str = fnStackNameArr[counter++]) != NULL) { 1.71 + PRUint32 len = strlen(str); 1.72 + for( i = 0; i < len; i++ ) { 1.73 + rvc[ i % sizeof(rv) ] ^= *str; 1.74 + str++; 1.75 + } 1.76 + } 1.77 + 1.78 + return rv; 1.79 +} 1.80 + 1.81 +#endif /* PKIX_OBJECT_LEAK_TEST */ 1.82 + 1.83 +/* 1.84 + * FUNCTION: pkix_IsCertSelfIssued 1.85 + * DESCRIPTION: 1.86 + * 1.87 + * Checks whether the Cert pointed to by "cert" is self-issued and stores the 1.88 + * Boolean result at "pSelfIssued". A Cert is considered self-issued if the 1.89 + * Cert's issuer matches the Cert's subject. If the subject or issuer is 1.90 + * not specified, a PKIX_FALSE is returned. 1.91 + * 1.92 + * PARAMETERS: 1.93 + * "cert" 1.94 + * Address of Cert used to determine whether Cert is self-issued. 1.95 + * Must be non-NULL. 1.96 + * "pSelfIssued" 1.97 + * Address where Boolean will be stored. Must be non-NULL. 1.98 + * "plContext" 1.99 + * Platform-specific context pointer. 1.100 + * THREAD SAFETY: 1.101 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.102 + * RETURNS: 1.103 + * Returns NULL if the function succeeds. 1.104 + * Returns a Cert Error if the function fails in a non-fatal way. 1.105 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.106 + */ 1.107 +PKIX_Error * 1.108 +pkix_IsCertSelfIssued( 1.109 + PKIX_PL_Cert *cert, 1.110 + PKIX_Boolean *pSelfIssued, 1.111 + void *plContext) 1.112 +{ 1.113 + PKIX_PL_X500Name *subject = NULL; 1.114 + PKIX_PL_X500Name *issuer = NULL; 1.115 + 1.116 + PKIX_ENTER(CERT, "pkix_IsCertSelfIssued"); 1.117 + PKIX_NULLCHECK_TWO(cert, pSelfIssued); 1.118 + 1.119 + PKIX_CHECK(PKIX_PL_Cert_GetSubject(cert, &subject, plContext), 1.120 + PKIX_CERTGETSUBJECTFAILED); 1.121 + 1.122 + PKIX_CHECK(PKIX_PL_Cert_GetIssuer(cert, &issuer, plContext), 1.123 + PKIX_CERTGETISSUERFAILED); 1.124 + 1.125 + if (subject == NULL || issuer == NULL) { 1.126 + *pSelfIssued = PKIX_FALSE; 1.127 + } else { 1.128 + 1.129 + PKIX_CHECK(PKIX_PL_X500Name_Match 1.130 + (subject, issuer, pSelfIssued, plContext), 1.131 + PKIX_X500NAMEMATCHFAILED); 1.132 + } 1.133 + 1.134 +cleanup: 1.135 + PKIX_DECREF(subject); 1.136 + PKIX_DECREF(issuer); 1.137 + 1.138 + PKIX_RETURN(CERT); 1.139 +} 1.140 + 1.141 +/* 1.142 + * FUNCTION: pkix_Throw 1.143 + * DESCRIPTION: 1.144 + * 1.145 + * Creates an Error using the value of "errorCode", the character array 1.146 + * pointed to by "funcName", the character array pointed to by "errorText", 1.147 + * and the Error pointed to by "cause" (if any), and stores it at "pError". 1.148 + * 1.149 + * If "cause" is not NULL and has an errorCode of "PKIX_FATAL_ERROR", 1.150 + * then there is no point creating a new Error object. Rather, we simply 1.151 + * store "cause" at "pError". 1.152 + * 1.153 + * PARAMETERS: 1.154 + * "errorCode" 1.155 + * Value of error code. 1.156 + * "funcName" 1.157 + * Address of EscASCII array representing name of function throwing error. 1.158 + * Must be non-NULL. 1.159 + * "errnum" 1.160 + * PKIX_ERRMSGNUM of error description for new error. 1.161 + * "cause" 1.162 + * Address of Error representing error's cause. 1.163 + * "pError" 1.164 + * Address where object pointer will be stored. Must be non-NULL. 1.165 + * "plContext" 1.166 + * Platform-specific context pointer. 1.167 + * THREAD SAFETY: 1.168 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.169 + * RETURNS: 1.170 + * Returns NULL if the function succeeds. 1.171 + * Returns an Error Error if the function fails in a non-fatal way. 1.172 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.173 + */ 1.174 +PKIX_Error * 1.175 +pkix_Throw( 1.176 + PKIX_ERRORCLASS errorClass, 1.177 + const char *funcName, 1.178 + PKIX_ERRORCODE errorCode, 1.179 + PKIX_ERRORCLASS overrideClass, 1.180 + PKIX_Error *cause, 1.181 + PKIX_Error **pError, 1.182 + void *plContext) 1.183 +{ 1.184 + PKIX_Error *error = NULL; 1.185 + 1.186 + PKIX_ENTER(ERROR, "pkix_Throw"); 1.187 + PKIX_NULLCHECK_TWO(funcName, pError); 1.188 + 1.189 + *pError = NULL; 1.190 + 1.191 +#ifdef PKIX_OBJECT_LEAK_TEST 1.192 + noErrorState = PKIX_TRUE; 1.193 + if (pkixLog) { 1.194 +#ifdef PKIX_ERROR_DESCRIPTION 1.195 + PR_LOG(pkixLog, 4, ("Error in function \"%s\":\"%s\" with cause \"%s\"\n", 1.196 + funcName, PKIX_ErrorText[errorCode], 1.197 + (cause ? PKIX_ErrorText[cause->errCode] : "null"))); 1.198 +#else 1.199 + PR_LOG(pkixLog, 4, ("Error in function \"%s\": error code \"%d\"\n", 1.200 + funcName, errorCode)); 1.201 +#endif /* PKIX_ERROR_DESCRIPTION */ 1.202 + PORT_Assert(strcmp(funcName, "PKIX_PL_Object_DecRef")); 1.203 + } 1.204 +#endif /* PKIX_OBJECT_LEAK_TEST */ 1.205 + 1.206 + /* if cause has error class of PKIX_FATAL_ERROR, return immediately */ 1.207 + if (cause) { 1.208 + if (cause->errClass == PKIX_FATAL_ERROR){ 1.209 + PKIX_INCREF(cause); 1.210 + *pError = cause; 1.211 + goto cleanup; 1.212 + } 1.213 + } 1.214 + 1.215 + if (overrideClass == PKIX_FATAL_ERROR){ 1.216 + errorClass = overrideClass; 1.217 + } 1.218 + 1.219 + pkixTempResult = PKIX_Error_Create(errorClass, cause, NULL, 1.220 + errorCode, &error, plContext); 1.221 + 1.222 + if (!pkixTempResult) { 1.223 + /* Setting plErr error code: 1.224 + * get it from PORT_GetError if it is a leaf error and 1.225 + * default error code does not exist(eq 0) */ 1.226 + if (!cause && !error->plErr) { 1.227 + error->plErr = PKIX_PL_GetPLErrorCode(); 1.228 + } 1.229 + } 1.230 + 1.231 + *pError = error; 1.232 + 1.233 +cleanup: 1.234 + 1.235 + PKIX_DEBUG_EXIT(ERROR); 1.236 + pkixErrorClass = 0; 1.237 +#ifdef PKIX_OBJECT_LEAK_TEST 1.238 + noErrorState = PKIX_FALSE; 1.239 + 1.240 + if (runningLeakTest && fnStackNameArr) { 1.241 + PR_LOG(pkixLog, 5, 1.242 + ("%s%*s<- %s(%d) - %s\n", (errorGenerated ? "*" : " "), 1.243 + stackPosition, " ", fnStackNameArr[stackPosition], 1.244 + stackPosition, myFuncName)); 1.245 + fnStackNameArr[stackPosition--] = NULL; 1.246 + } 1.247 +#endif /* PKIX_OBJECT_LEAK_TEST */ 1.248 + return (pkixTempResult); 1.249 +} 1.250 + 1.251 +/* 1.252 + * FUNCTION: pkix_CheckTypes 1.253 + * DESCRIPTION: 1.254 + * 1.255 + * Checks that the types of the Object pointed to by "first" and the Object 1.256 + * pointed to by "second" are both equal to the value of "type". If they 1.257 + * are not equal, a PKIX_Error is returned. 1.258 + * 1.259 + * PARAMETERS: 1.260 + * "first" 1.261 + * Address of first Object. Must be non-NULL. 1.262 + * "second" 1.263 + * Address of second Object. Must be non-NULL. 1.264 + * "type" 1.265 + * Value of type to check against. 1.266 + * "plContext" 1.267 + * Platform-specific context pointer. 1.268 + * THREAD SAFETY: 1.269 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.270 + * RETURNS: 1.271 + * Returns NULL if the function succeeds. 1.272 + * Returns an Error Error if the function fails in a non-fatal way. 1.273 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.274 + */ 1.275 +PKIX_Error * 1.276 +pkix_CheckTypes( 1.277 + PKIX_PL_Object *first, 1.278 + PKIX_PL_Object *second, 1.279 + PKIX_UInt32 type, 1.280 + void *plContext) 1.281 +{ 1.282 + PKIX_UInt32 firstType, secondType; 1.283 + 1.284 + PKIX_ENTER(OBJECT, "pkix_CheckTypes"); 1.285 + PKIX_NULLCHECK_TWO(first, second); 1.286 + 1.287 + PKIX_CHECK(PKIX_PL_Object_GetType(first, &firstType, plContext), 1.288 + PKIX_COULDNOTGETFIRSTOBJECTTYPE); 1.289 + 1.290 + PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext), 1.291 + PKIX_COULDNOTGETSECONDOBJECTTYPE); 1.292 + 1.293 + if ((firstType != type)||(firstType != secondType)) { 1.294 + PKIX_ERROR(PKIX_OBJECTTYPESDONOTMATCH); 1.295 + } 1.296 + 1.297 +cleanup: 1.298 + 1.299 + PKIX_RETURN(OBJECT); 1.300 +} 1.301 + 1.302 +/* 1.303 + * FUNCTION: pkix_CheckType 1.304 + * DESCRIPTION: 1.305 + * 1.306 + * Checks that the type of the Object pointed to by "object" is equal to the 1.307 + * value of "type". If it is not equal, a PKIX_Error is returned. 1.308 + * 1.309 + * PARAMETERS: 1.310 + * "object" 1.311 + * Address of Object. Must be non-NULL. 1.312 + * "type" 1.313 + * Value of type to check against. 1.314 + * "plContext" 1.315 + * Platform-specific context pointer. 1.316 + * THREAD SAFETY: 1.317 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.318 + * RETURNS: 1.319 + * Returns NULL if the function succeeds. 1.320 + * Returns an Error Error if the function fails in a non-fatal way. 1.321 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.322 + */ 1.323 +PKIX_Error * 1.324 +pkix_CheckType( 1.325 + PKIX_PL_Object *object, 1.326 + PKIX_UInt32 type, 1.327 + void *plContext) 1.328 +{ 1.329 + return (pkix_CheckTypes(object, object, type, plContext)); 1.330 +} 1.331 + 1.332 +/* 1.333 + * FUNCTION: pkix_hash 1.334 + * DESCRIPTION: 1.335 + * 1.336 + * Computes a hash value for "length" bytes starting at the array of bytes 1.337 + * pointed to by "bytes" and stores the result at "pHash". 1.338 + * 1.339 + * XXX To speed this up, we could probably read 32 bits at a time from 1.340 + * bytes (maybe even 64 bits on some platforms) 1.341 + * 1.342 + * PARAMETERS: 1.343 + * "bytes" 1.344 + * Address of array of bytes to hash. Must be non-NULL. 1.345 + * "length" 1.346 + * Number of bytes to hash. 1.347 + * "pHash" 1.348 + * Address where object pointer will be stored. Must be non-NULL. 1.349 + * "plContext" 1.350 + * Platform-specific context pointer. 1.351 + * THREAD SAFETY: 1.352 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.353 + * RETURNS: 1.354 + * Returns NULL if the function succeeds. 1.355 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.356 + */ 1.357 +PKIX_Error * 1.358 +pkix_hash( 1.359 + const unsigned char *bytes, 1.360 + PKIX_UInt32 length, 1.361 + PKIX_UInt32 *pHash, 1.362 + void *plContext) 1.363 +{ 1.364 + PKIX_UInt32 i; 1.365 + PKIX_UInt32 hash; 1.366 + 1.367 + PKIX_ENTER(OBJECT, "pkix_hash"); 1.368 + if (length != 0) { 1.369 + PKIX_NULLCHECK_ONE(bytes); 1.370 + } 1.371 + PKIX_NULLCHECK_ONE(pHash); 1.372 + 1.373 + hash = 0; 1.374 + for (i = 0; i < length; i++) { 1.375 + /* hash = 31 * hash + bytes[i]; */ 1.376 + hash = (hash << 5) - hash + bytes[i]; 1.377 + } 1.378 + 1.379 + *pHash = hash; 1.380 + 1.381 + PKIX_RETURN(OBJECT); 1.382 +} 1.383 + 1.384 +/* 1.385 + * FUNCTION: pkix_countArray 1.386 + * DESCRIPTION: 1.387 + * 1.388 + * Counts the number of elements in the null-terminated array of pointers 1.389 + * pointed to by "array" and returns the result. 1.390 + * 1.391 + * PARAMETERS 1.392 + * "array" 1.393 + * Address of null-terminated array of pointers. 1.394 + * THREAD SAFETY: 1.395 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.396 + * RETURNS: 1.397 + * Returns the number of elements in the array. 1.398 + */ 1.399 +PKIX_UInt32 1.400 +pkix_countArray(void **array) 1.401 +{ 1.402 + PKIX_UInt32 count = 0; 1.403 + 1.404 + if (array) { 1.405 + while (*array++) { 1.406 + count++; 1.407 + } 1.408 + } 1.409 + return (count); 1.410 +} 1.411 + 1.412 +/* 1.413 + * FUNCTION: pkix_duplicateImmutable 1.414 + * DESCRIPTION: 1.415 + * 1.416 + * Convenience callback function used for duplicating immutable objects. 1.417 + * Since the objects can not be modified, this function simply increments the 1.418 + * reference count on the object, and returns a reference to that object. 1.419 + * 1.420 + * (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h) 1.421 + */ 1.422 +PKIX_Error * 1.423 +pkix_duplicateImmutable( 1.424 + PKIX_PL_Object *object, 1.425 + PKIX_PL_Object **pNewObject, 1.426 + void *plContext) 1.427 +{ 1.428 + PKIX_ENTER(OBJECT, "pkix_duplicateImmutable"); 1.429 + PKIX_NULLCHECK_TWO(object, pNewObject); 1.430 + 1.431 + PKIX_INCREF(object); 1.432 + 1.433 + *pNewObject = object; 1.434 + 1.435 +cleanup: 1.436 + PKIX_RETURN(OBJECT); 1.437 +} 1.438 + 1.439 +/* --String-Encoding-Conversion-Functions------------------------ */ 1.440 + 1.441 +/* 1.442 + * FUNCTION: pkix_hex2i 1.443 + * DESCRIPTION: 1.444 + * 1.445 + * Converts hexadecimal character "c" to its integer value and returns result. 1.446 + * 1.447 + * PARAMETERS 1.448 + * "c" 1.449 + * Character to convert to a hex value. 1.450 + * THREAD SAFETY: 1.451 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.452 + * RETURNS: 1.453 + * The hexadecimal value of "c". Otherwise -1. (Unsigned 0xFFFFFFFF). 1.454 + */ 1.455 +PKIX_UInt32 1.456 +pkix_hex2i(char c) 1.457 +{ 1.458 + if ((c >= '0')&&(c <= '9')) 1.459 + return (c-'0'); 1.460 + else if ((c >= 'a')&&(c <= 'f')) 1.461 + return (c-'a'+10); 1.462 + else if ((c >= 'A')&&(c <= 'F')) 1.463 + return (c-'A'+10); 1.464 + else 1.465 + return ((PKIX_UInt32)(-1)); 1.466 +} 1.467 + 1.468 +/* 1.469 + * FUNCTION: pkix_i2hex 1.470 + * DESCRIPTION: 1.471 + * 1.472 + * Converts integer value "digit" to its ASCII hex value 1.473 + * 1.474 + * PARAMETERS 1.475 + * "digit" 1.476 + * Value of integer to convert to ASCII hex value. Must be 0-15. 1.477 + * THREAD SAFETY: 1.478 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.479 + * RETURNS: 1.480 + * The ASCII hexadecimal value of "digit". 1.481 + */ 1.482 +char 1.483 +pkix_i2hex(char digit) 1.484 +{ 1.485 + if ((digit >= 0)&&(digit <= 9)) 1.486 + return (digit+'0'); 1.487 + else if ((digit >= 0xa)&&(digit <= 0xf)) 1.488 + return (digit - 10 + 'a'); 1.489 + else 1.490 + return (-1); 1.491 +} 1.492 + 1.493 +/* 1.494 + * FUNCTION: pkix_isPlaintext 1.495 + * DESCRIPTION: 1.496 + * 1.497 + * Returns whether character "c" is plaintext using EscASCII or EscASCII_Debug 1.498 + * depending on the value of "debug". 1.499 + * 1.500 + * In EscASCII, [01, 7E] except '&' are plaintext. 1.501 + * In EscASCII_Debug [20, 7E] except '&' are plaintext. 1.502 + * 1.503 + * PARAMETERS: 1.504 + * "c" 1.505 + * Character to check. 1.506 + * "debug" 1.507 + * Value of debug flag. 1.508 + * THREAD SAFETY: 1.509 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.510 + * RETURNS: 1.511 + * True if "c" is plaintext. 1.512 + */ 1.513 +PKIX_Boolean 1.514 +pkix_isPlaintext(unsigned char c, PKIX_Boolean debug) { 1.515 + return ((c >= 0x01)&&(c <= 0x7E)&&(c != '&')&&(!debug || (c >= 20))); 1.516 +} 1.517 + 1.518 +/* --Cache-Functions------------------------ */ 1.519 + 1.520 +/* 1.521 + * FUNCTION: pkix_CacheCertChain_Lookup 1.522 + * DESCRIPTION: 1.523 + * 1.524 + * Look up CertChain Hash Table for a cached BuildResult based on "targetCert" 1.525 + * and "anchors" as the hash keys. If there is no item to match the key, 1.526 + * PKIX_FALSE is stored at "pFound". If an item is found, its cache time is 1.527 + * compared to "testDate". If expired, the item is removed and PKIX_FALSE is 1.528 + * stored at "pFound". Otherwise, PKIX_TRUE is stored at "pFound" and the 1.529 + * BuildResult is stored at "pBuildResult". 1.530 + * The hashtable is maintained in the following ways: 1.531 + * 1) When creating the hashtable, maximum bucket size can be specified (0 for 1.532 + * unlimited). If items in a bucket reaches its full size, an new addition 1.533 + * will trigger the removal of the old as FIFO sequence. 1.534 + * 2) A PKIX_PL_Date created with current time offset by constant 1.535 + * CACHE_ITEM_PERIOD_SECONDS is attached to each item in the Hash Table. 1.536 + * When an item is retrieved, this date is compared against "testDate" for 1.537 + * validity. If comparison indicates this item is expired, the item is 1.538 + * removed from the bucket. 1.539 + * 1.540 + * PARAMETERS: 1.541 + * "targetCert" 1.542 + * Address of Target Cert as key to retrieve this CertChain. Must be 1.543 + * non-NULL. 1.544 + * "anchors" 1.545 + * Address of PKIX_List of "anchors" is used as key to retrive CertChain. 1.546 + * Must be non-NULL. 1.547 + * "testDate" 1.548 + * Address of PKIX_PL_Date for verifying time validity and cache validity. 1.549 + * May be NULL. If testDate is NULL, this cache item will not be out-dated. 1.550 + * "pFound" 1.551 + * Address of PKIX_Boolean indicating valid data is found. 1.552 + * Must be non-NULL. 1.553 + * "pBuildResult" 1.554 + * Address where BuildResult will be stored. Must be non-NULL. 1.555 + * "plContext" 1.556 + * Platform-specific context pointer. 1.557 + * THREAD SAFETY: 1.558 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.559 + * RETURNS: 1.560 + * Returns NULL if the function succeeds. 1.561 + * Returns an Error Error if the function fails in a non-fatal way. 1.562 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.563 + */ 1.564 +PKIX_Error * 1.565 +pkix_CacheCertChain_Lookup( 1.566 + PKIX_PL_Cert* targetCert, 1.567 + PKIX_List* anchors, 1.568 + PKIX_PL_Date *testDate, 1.569 + PKIX_Boolean *pFound, 1.570 + PKIX_BuildResult **pBuildResult, 1.571 + void *plContext) 1.572 +{ 1.573 + PKIX_List *cachedValues = NULL; 1.574 + PKIX_List *cachedKeys = NULL; 1.575 + PKIX_Error *cachedCertChainError = NULL; 1.576 + PKIX_PL_Date *cacheValidUntilDate = NULL; 1.577 + PKIX_PL_Date *validityDate = NULL; 1.578 + PKIX_Int32 cmpValidTimeResult = 0; 1.579 + PKIX_Int32 cmpCacheTimeResult = 0; 1.580 + 1.581 + PKIX_ENTER(BUILD, "pkix_CacheCertChain_Lookup"); 1.582 + 1.583 + PKIX_NULLCHECK_FOUR(targetCert, anchors, pFound, pBuildResult); 1.584 + 1.585 + *pFound = PKIX_FALSE; 1.586 + 1.587 + /* use trust anchors and target cert as hash key */ 1.588 + 1.589 + PKIX_CHECK(PKIX_List_Create(&cachedKeys, plContext), 1.590 + PKIX_LISTCREATEFAILED); 1.591 + 1.592 + PKIX_CHECK(PKIX_List_AppendItem 1.593 + (cachedKeys, 1.594 + (PKIX_PL_Object *)targetCert, 1.595 + plContext), 1.596 + PKIX_LISTAPPENDITEMFAILED); 1.597 + 1.598 + PKIX_CHECK(PKIX_List_AppendItem 1.599 + (cachedKeys, 1.600 + (PKIX_PL_Object *)anchors, 1.601 + plContext), 1.602 + PKIX_LISTAPPENDITEMFAILED); 1.603 + 1.604 + cachedCertChainError = PKIX_PL_HashTable_Lookup 1.605 + (cachedCertChainTable, 1.606 + (PKIX_PL_Object *) cachedKeys, 1.607 + (PKIX_PL_Object **) &cachedValues, 1.608 + plContext); 1.609 + 1.610 + pkix_ccLookupCount++; 1.611 + 1.612 + /* retrieve data from hashed value list */ 1.613 + 1.614 + if (cachedValues != NULL && cachedCertChainError == NULL) { 1.615 + 1.616 + PKIX_CHECK(PKIX_List_GetItem 1.617 + (cachedValues, 1.618 + 0, 1.619 + (PKIX_PL_Object **) &cacheValidUntilDate, 1.620 + plContext), 1.621 + PKIX_LISTGETITEMFAILED); 1.622 + 1.623 + /* check validity time and cache age time */ 1.624 + PKIX_CHECK(PKIX_List_GetItem 1.625 + (cachedValues, 1.626 + 1, 1.627 + (PKIX_PL_Object **) &validityDate, 1.628 + plContext), 1.629 + PKIX_LISTGETITEMFAILED); 1.630 + 1.631 + /* if testDate is not set, this cache item is not out-dated */ 1.632 + if (testDate) { 1.633 + 1.634 + PKIX_CHECK(PKIX_PL_Object_Compare 1.635 + ((PKIX_PL_Object *)testDate, 1.636 + (PKIX_PL_Object *)cacheValidUntilDate, 1.637 + &cmpCacheTimeResult, 1.638 + plContext), 1.639 + PKIX_OBJECTCOMPARATORFAILED); 1.640 + 1.641 + PKIX_CHECK(PKIX_PL_Object_Compare 1.642 + ((PKIX_PL_Object *)testDate, 1.643 + (PKIX_PL_Object *)validityDate, 1.644 + &cmpValidTimeResult, 1.645 + plContext), 1.646 + PKIX_OBJECTCOMPARATORFAILED); 1.647 + } 1.648 + 1.649 + /* certs' date are all valid and cache item is not old */ 1.650 + if (cmpValidTimeResult <= 0 && cmpCacheTimeResult <=0) { 1.651 + 1.652 + PKIX_CHECK(PKIX_List_GetItem 1.653 + (cachedValues, 1.654 + 2, 1.655 + (PKIX_PL_Object **) pBuildResult, 1.656 + plContext), 1.657 + PKIX_LISTGETITEMFAILED); 1.658 + 1.659 + *pFound = PKIX_TRUE; 1.660 + 1.661 + } else { 1.662 + 1.663 + pkix_ccRemoveCount++; 1.664 + *pFound = PKIX_FALSE; 1.665 + 1.666 + /* out-dated item, remove it from cache */ 1.667 + PKIX_CHECK(PKIX_PL_HashTable_Remove 1.668 + (cachedCertChainTable, 1.669 + (PKIX_PL_Object *) cachedKeys, 1.670 + plContext), 1.671 + PKIX_HASHTABLEREMOVEFAILED); 1.672 + } 1.673 + } 1.674 + 1.675 +cleanup: 1.676 + 1.677 + PKIX_DECREF(cachedValues); 1.678 + PKIX_DECREF(cachedKeys); 1.679 + PKIX_DECREF(cachedCertChainError); 1.680 + PKIX_DECREF(cacheValidUntilDate); 1.681 + PKIX_DECREF(validityDate); 1.682 + 1.683 + PKIX_RETURN(BUILD); 1.684 + 1.685 +} 1.686 + 1.687 +/* 1.688 + * FUNCTION: pkix_CacheCertChain_Remove 1.689 + * DESCRIPTION: 1.690 + * 1.691 + * Remove CertChain Hash Table entry based on "targetCert" and "anchors" 1.692 + * as the hash keys. If there is no item to match the key, no action is 1.693 + * taken. 1.694 + * The hashtable is maintained in the following ways: 1.695 + * 1) When creating the hashtable, maximum bucket size can be specified (0 for 1.696 + * unlimited). If items in a bucket reaches its full size, an new addition 1.697 + * will trigger the removal of the old as FIFO sequence. 1.698 + * 2) A PKIX_PL_Date created with current time offset by constant 1.699 + * CACHE_ITEM_PERIOD_SECONDS is attached to each item in the Hash Table. 1.700 + * When an item is retrieved, this date is compared against "testDate" for 1.701 + * validity. If comparison indicates this item is expired, the item is 1.702 + * removed from the bucket. 1.703 + * 1.704 + * PARAMETERS: 1.705 + * "targetCert" 1.706 + * Address of Target Cert as key to retrieve this CertChain. Must be 1.707 + * non-NULL. 1.708 + * "anchors" 1.709 + * Address of PKIX_List of "anchors" is used as key to retrive CertChain. 1.710 + * Must be non-NULL. 1.711 + * "plContext" 1.712 + * Platform-specific context pointer. 1.713 + * THREAD SAFETY: 1.714 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.715 + * RETURNS: 1.716 + * Returns NULL if the function succeeds. 1.717 + * Returns an Error Error if the function fails in a non-fatal way. 1.718 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.719 + */ 1.720 +PKIX_Error * 1.721 +pkix_CacheCertChain_Remove( 1.722 + PKIX_PL_Cert* targetCert, 1.723 + PKIX_List* anchors, 1.724 + void *plContext) 1.725 +{ 1.726 + PKIX_List *cachedKeys = NULL; 1.727 + 1.728 + PKIX_ENTER(BUILD, "pkix_CacheCertChain_Remove"); 1.729 + PKIX_NULLCHECK_TWO(targetCert, anchors); 1.730 + 1.731 + /* use trust anchors and target cert as hash key */ 1.732 + 1.733 + PKIX_CHECK(PKIX_List_Create(&cachedKeys, plContext), 1.734 + PKIX_LISTCREATEFAILED); 1.735 + 1.736 + PKIX_CHECK(PKIX_List_AppendItem 1.737 + (cachedKeys, 1.738 + (PKIX_PL_Object *)targetCert, 1.739 + plContext), 1.740 + PKIX_LISTAPPENDITEMFAILED); 1.741 + 1.742 + PKIX_CHECK(PKIX_List_AppendItem 1.743 + (cachedKeys, 1.744 + (PKIX_PL_Object *)anchors, 1.745 + plContext), 1.746 + PKIX_LISTAPPENDITEMFAILED); 1.747 + 1.748 + PKIX_CHECK_ONLY_FATAL(PKIX_PL_HashTable_Remove 1.749 + (cachedCertChainTable, 1.750 + (PKIX_PL_Object *) cachedKeys, 1.751 + plContext), 1.752 + PKIX_HASHTABLEREMOVEFAILED); 1.753 + 1.754 + pkix_ccRemoveCount++; 1.755 + 1.756 +cleanup: 1.757 + 1.758 + PKIX_DECREF(cachedKeys); 1.759 + 1.760 + PKIX_RETURN(BUILD); 1.761 + 1.762 +} 1.763 + 1.764 +/* 1.765 + * FUNCTION: pkix_CacheCertChain_Add 1.766 + * DESCRIPTION: 1.767 + * 1.768 + * Add a BuildResult to the CertChain Hash Table for a "buildResult" with 1.769 + * "targetCert" and "anchors" as the hash keys. 1.770 + * "validityDate" is the most restricted notAfter date of all Certs in 1.771 + * this CertChain and is verified when this BuildChain is retrieved. 1.772 + * The hashtable is maintained in the following ways: 1.773 + * 1) When creating the hashtable, maximum bucket size can be specified (0 for 1.774 + * unlimited). If items in a bucket reaches its full size, an new addition 1.775 + * will trigger the removal of the old as FIFO sequence. 1.776 + * 2) A PKIX_PL_Date created with current time offset by constant 1.777 + * CACHE_ITEM_PERIOD_SECONDS is attached to each item in the Hash Table. 1.778 + * When an item is retrieved, this date is compared against "testDate" for 1.779 + * validity. If comparison indicates this item is expired, the item is 1.780 + * removed from the bucket. 1.781 + * 1.782 + * PARAMETERS: 1.783 + * "targetCert" 1.784 + * Address of Target Cert as key to retrieve this CertChain. Must be 1.785 + * non-NULL. 1.786 + * "anchors" 1.787 + * Address of PKIX_List of "anchors" is used as key to retrive CertChain. 1.788 + * Must be non-NULL. 1.789 + * "validityDate" 1.790 + * Address of PKIX_PL_Date contains the most restriced notAfter time of 1.791 + * all "certs". Must be non-NULL. 1.792 + * Address of PKIX_Boolean indicating valid data is found. 1.793 + * Must be non-NULL. 1.794 + * "buildResult" 1.795 + * Address of BuildResult to be cached. Must be non-NULL. 1.796 + * "plContext" 1.797 + * Platform-specific context pointer. 1.798 + * THREAD SAFETY: 1.799 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.800 + * RETURNS: 1.801 + * Returns NULL if the function succeeds. 1.802 + * Returns an Error Error if the function fails in a non-fatal way. 1.803 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.804 + */ 1.805 +PKIX_Error * 1.806 +pkix_CacheCertChain_Add( 1.807 + PKIX_PL_Cert* targetCert, 1.808 + PKIX_List* anchors, 1.809 + PKIX_PL_Date *validityDate, 1.810 + PKIX_BuildResult *buildResult, 1.811 + void *plContext) 1.812 +{ 1.813 + PKIX_List *cachedValues = NULL; 1.814 + PKIX_List *cachedKeys = NULL; 1.815 + PKIX_Error *cachedCertChainError = NULL; 1.816 + PKIX_PL_Date *cacheValidUntilDate = NULL; 1.817 + 1.818 + PKIX_ENTER(BUILD, "pkix_CacheCertChain_Add"); 1.819 + 1.820 + PKIX_NULLCHECK_FOUR(targetCert, anchors, validityDate, buildResult); 1.821 + 1.822 + PKIX_CHECK(PKIX_List_Create(&cachedKeys, plContext), 1.823 + PKIX_LISTCREATEFAILED); 1.824 + 1.825 + PKIX_CHECK(PKIX_List_AppendItem 1.826 + (cachedKeys, (PKIX_PL_Object *)targetCert, plContext), 1.827 + PKIX_LISTAPPENDITEMFAILED); 1.828 + 1.829 + PKIX_CHECK(PKIX_List_AppendItem 1.830 + (cachedKeys, (PKIX_PL_Object *)anchors, plContext), 1.831 + PKIX_LISTAPPENDITEMFAILED); 1.832 + 1.833 + PKIX_CHECK(PKIX_List_Create(&cachedValues, plContext), 1.834 + PKIX_LISTCREATEFAILED); 1.835 + 1.836 + PKIX_CHECK(PKIX_PL_Date_Create_CurrentOffBySeconds 1.837 + (CACHE_ITEM_PERIOD_SECONDS, 1.838 + &cacheValidUntilDate, 1.839 + plContext), 1.840 + PKIX_DATECREATECURRENTOFFBYSECONDSFAILED); 1.841 + 1.842 + PKIX_CHECK(PKIX_List_AppendItem 1.843 + (cachedValues, 1.844 + (PKIX_PL_Object *)cacheValidUntilDate, 1.845 + plContext), 1.846 + PKIX_LISTAPPENDITEMFAILED); 1.847 + 1.848 + PKIX_CHECK(PKIX_List_AppendItem 1.849 + (cachedValues, (PKIX_PL_Object *)validityDate, plContext), 1.850 + PKIX_LISTAPPENDITEMFAILED); 1.851 + 1.852 + PKIX_CHECK(PKIX_List_AppendItem 1.853 + (cachedValues, (PKIX_PL_Object *)buildResult, plContext), 1.854 + PKIX_LISTAPPENDITEMFAILED); 1.855 + 1.856 + cachedCertChainError = PKIX_PL_HashTable_Add 1.857 + (cachedCertChainTable, 1.858 + (PKIX_PL_Object *) cachedKeys, 1.859 + (PKIX_PL_Object *) cachedValues, 1.860 + plContext); 1.861 + 1.862 + pkix_ccAddCount++; 1.863 + 1.864 + if (cachedCertChainError != NULL) { 1.865 + PKIX_DEBUG("PKIX_PL_HashTable_Add for CertChain skipped: " 1.866 + "entry existed\n"); 1.867 + } 1.868 + 1.869 +cleanup: 1.870 + 1.871 + PKIX_DECREF(cachedValues); 1.872 + PKIX_DECREF(cachedKeys); 1.873 + PKIX_DECREF(cachedCertChainError); 1.874 + PKIX_DECREF(cacheValidUntilDate); 1.875 + 1.876 + PKIX_RETURN(BUILD); 1.877 +} 1.878 + 1.879 +/* 1.880 + * FUNCTION: pkix_CacheCert_Lookup 1.881 + * DESCRIPTION: 1.882 + * 1.883 + * Look up Cert Hash Table for a cached item based on "store" and Subject in 1.884 + * "certSelParams" as the hash keys and returns values Certs in "pCerts". 1.885 + * If there isn't an item to match the key, a PKIX_FALSE is returned at 1.886 + * "pFound". The item's cache time is verified with "testDate". If out-dated, 1.887 + * this item is removed and PKIX_FALSE is returned at "pFound". 1.888 + * This hashtable is maintained in the following ways: 1.889 + * 1) When creating the hashtable, maximum bucket size can be specified (0 for 1.890 + * unlimited). If items in a bucket reaches its full size, an new addition 1.891 + * will trigger the removal of the old as FIFO sequence. 1.892 + * 2) A PKIX_PL_Date created with current time offset by constant 1.893 + * CACHE_ITEM_PERIOD_SECONDS is attached to each item in the Hash Table. 1.894 + * If the CertStore this Cert is from is a trusted one, the cache period is 1.895 + * shorter so cache can be updated more frequently. 1.896 + * When an item is retrieved, this date is compared against "testDate" for 1.897 + * validity. If comparison indicates this item is expired, the item is 1.898 + * removed from the bucket. 1.899 + * 1.900 + * PARAMETERS: 1.901 + * "store" 1.902 + * Address of CertStore as key to retrieve this CertChain. Must be 1.903 + * non-NULL. 1.904 + * "certSelParams" 1.905 + * Address of ComCertSelParams that its subject is used as key to retrieve 1.906 + * this CertChain. Must be non-NULL. 1.907 + * "testDate" 1.908 + * Address of PKIX_PL_Date for verifying time cache validity. 1.909 + * Must be non-NULL. If testDate is NULL, this cache item won't be out 1.910 + * dated. 1.911 + * "pFound" 1.912 + * Address of KPKIX_Boolean indicating valid data is found. 1.913 + * Must be non-NULL. 1.914 + * "pCerts" 1.915 + * Address PKIX_List where the CertChain will be stored. Must be no-NULL. 1.916 + * "plContext" 1.917 + * Platform-specific context pointer. 1.918 + * THREAD SAFETY: 1.919 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.920 + * RETURNS: 1.921 + * Returns NULL if the function succeeds. 1.922 + * Returns an Error Error if the function fails in a non-fatal way. 1.923 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.924 + */ 1.925 +PKIX_Error * 1.926 +pkix_CacheCert_Lookup( 1.927 + PKIX_CertStore *store, 1.928 + PKIX_ComCertSelParams *certSelParams, 1.929 + PKIX_PL_Date *testDate, 1.930 + PKIX_Boolean *pFound, 1.931 + PKIX_List** pCerts, 1.932 + void *plContext) 1.933 +{ 1.934 + PKIX_PL_Cert *cert = NULL; 1.935 + PKIX_List *cachedKeys = NULL; 1.936 + PKIX_List *cachedValues = NULL; 1.937 + PKIX_List *cachedCertList = NULL; 1.938 + PKIX_List *selCertList = NULL; 1.939 + PKIX_PL_X500Name *subject = NULL; 1.940 + PKIX_PL_Date *invalidAfterDate = NULL; 1.941 + PKIX_PL_Date *cacheValidUntilDate = NULL; 1.942 + PKIX_CertSelector *certSel = NULL; 1.943 + PKIX_Error *cachedCertError = NULL; 1.944 + PKIX_Error *selectorError = NULL; 1.945 + PKIX_CertSelector_MatchCallback selectorMatch = NULL; 1.946 + PKIX_Int32 cmpValidTimeResult = PKIX_FALSE; 1.947 + PKIX_Int32 cmpCacheTimeResult = 0; 1.948 + PKIX_UInt32 numItems = 0; 1.949 + PKIX_UInt32 i; 1.950 + 1.951 + PKIX_ENTER(BUILD, "pkix_CacheCert_Lookup"); 1.952 + PKIX_NULLCHECK_TWO(store, certSelParams); 1.953 + PKIX_NULLCHECK_TWO(pFound, pCerts); 1.954 + 1.955 + *pFound = PKIX_FALSE; 1.956 + 1.957 + PKIX_CHECK(PKIX_List_Create(&cachedKeys, plContext), 1.958 + PKIX_LISTCREATEFAILED); 1.959 + 1.960 + PKIX_CHECK(PKIX_List_AppendItem 1.961 + (cachedKeys, (PKIX_PL_Object *)store, plContext), 1.962 + PKIX_LISTAPPENDITEMFAILED); 1.963 + 1.964 + PKIX_CHECK(PKIX_ComCertSelParams_GetSubject 1.965 + (certSelParams, &subject, plContext), 1.966 + PKIX_COMCERTSELPARAMSGETSUBJECTFAILED); 1.967 + 1.968 + PKIX_NULLCHECK_ONE(subject); 1.969 + 1.970 + PKIX_CHECK(PKIX_List_AppendItem 1.971 + (cachedKeys, (PKIX_PL_Object *)subject, plContext), 1.972 + PKIX_LISTAPPENDITEMFAILED); 1.973 + 1.974 + cachedCertError = PKIX_PL_HashTable_Lookup 1.975 + (cachedCertTable, 1.976 + (PKIX_PL_Object *) cachedKeys, 1.977 + (PKIX_PL_Object **) &cachedValues, 1.978 + plContext); 1.979 + pkix_cLookupCount++; 1.980 + 1.981 + if (cachedValues != NULL && cachedCertError == NULL) { 1.982 + 1.983 + PKIX_CHECK(PKIX_List_GetItem 1.984 + (cachedValues, 1.985 + 0, 1.986 + (PKIX_PL_Object **) &cacheValidUntilDate, 1.987 + plContext), 1.988 + PKIX_LISTGETITEMFAILED); 1.989 + 1.990 + if (testDate) { 1.991 + PKIX_CHECK(PKIX_PL_Object_Compare 1.992 + ((PKIX_PL_Object *)testDate, 1.993 + (PKIX_PL_Object *)cacheValidUntilDate, 1.994 + &cmpCacheTimeResult, 1.995 + plContext), 1.996 + PKIX_OBJECTCOMPARATORFAILED); 1.997 + } 1.998 + 1.999 + if (cmpCacheTimeResult <= 0) { 1.1000 + 1.1001 + PKIX_CHECK(PKIX_List_GetItem 1.1002 + (cachedValues, 1.1003 + 1, 1.1004 + (PKIX_PL_Object **) &cachedCertList, 1.1005 + plContext), 1.1006 + PKIX_LISTGETITEMFAILED); 1.1007 + 1.1008 + /* 1.1009 + * Certs put on cache satifies only for Subject, 1.1010 + * user selector and ComCertSelParams to filter. 1.1011 + */ 1.1012 + PKIX_CHECK(PKIX_CertSelector_Create 1.1013 + (NULL, NULL, &certSel, plContext), 1.1014 + PKIX_CERTSELECTORCREATEFAILED); 1.1015 + 1.1016 + PKIX_CHECK(PKIX_CertSelector_SetCommonCertSelectorParams 1.1017 + (certSel, certSelParams, plContext), 1.1018 + PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED); 1.1019 + 1.1020 + PKIX_CHECK(PKIX_CertSelector_GetMatchCallback 1.1021 + (certSel, &selectorMatch, plContext), 1.1022 + PKIX_CERTSELECTORGETMATCHCALLBACKFAILED); 1.1023 + 1.1024 + PKIX_CHECK(PKIX_List_Create(&selCertList, plContext), 1.1025 + PKIX_LISTCREATEFAILED); 1.1026 + 1.1027 + /* 1.1028 + * If any of the Cert on the list is out-dated, invalidate 1.1029 + * this cache item. 1.1030 + */ 1.1031 + PKIX_CHECK(PKIX_List_GetLength 1.1032 + (cachedCertList, &numItems, plContext), 1.1033 + PKIX_LISTGETLENGTHFAILED); 1.1034 + 1.1035 + for (i = 0; i < numItems; i++){ 1.1036 + 1.1037 + PKIX_CHECK(PKIX_List_GetItem 1.1038 + (cachedCertList, 1.1039 + i, 1.1040 + (PKIX_PL_Object **)&cert, 1.1041 + plContext), 1.1042 + PKIX_LISTGETITEMFAILED); 1.1043 + 1.1044 + PKIX_CHECK(PKIX_PL_Cert_GetValidityNotAfter 1.1045 + (cert, &invalidAfterDate, plContext), 1.1046 + PKIX_CERTGETVALIDITYNOTAFTERFAILED); 1.1047 + 1.1048 + if (testDate) { 1.1049 + PKIX_CHECK(PKIX_PL_Object_Compare 1.1050 + ((PKIX_PL_Object *)invalidAfterDate, 1.1051 + (PKIX_PL_Object *)testDate, 1.1052 + &cmpValidTimeResult, 1.1053 + plContext), 1.1054 + PKIX_OBJECTCOMPARATORFAILED); 1.1055 + } 1.1056 + 1.1057 + if (cmpValidTimeResult < 0) { 1.1058 + 1.1059 + pkix_cRemoveCount++; 1.1060 + *pFound = PKIX_FALSE; 1.1061 + 1.1062 + /* one cert is out-dated, remove item from cache */ 1.1063 + PKIX_CHECK(PKIX_PL_HashTable_Remove 1.1064 + (cachedCertTable, 1.1065 + (PKIX_PL_Object *) cachedKeys, 1.1066 + plContext), 1.1067 + PKIX_HASHTABLEREMOVEFAILED); 1.1068 + goto cleanup; 1.1069 + } 1.1070 + 1.1071 + selectorError = selectorMatch(certSel, cert, plContext); 1.1072 + if (!selectorError){ 1.1073 + /* put on the return list */ 1.1074 + PKIX_CHECK(PKIX_List_AppendItem 1.1075 + (selCertList, 1.1076 + (PKIX_PL_Object *)cert, 1.1077 + plContext), 1.1078 + PKIX_LISTAPPENDITEMFAILED); 1.1079 + } else { 1.1080 + PKIX_DECREF(selectorError); 1.1081 + } 1.1082 + 1.1083 + PKIX_DECREF(cert); 1.1084 + PKIX_DECREF(invalidAfterDate); 1.1085 + 1.1086 + } 1.1087 + 1.1088 + if (*pFound) { 1.1089 + PKIX_INCREF(selCertList); 1.1090 + *pCerts = selCertList; 1.1091 + } 1.1092 + 1.1093 + } else { 1.1094 + 1.1095 + pkix_cRemoveCount++; 1.1096 + *pFound = PKIX_FALSE; 1.1097 + /* cache item is out-dated, remove it from cache */ 1.1098 + PKIX_CHECK(PKIX_PL_HashTable_Remove 1.1099 + (cachedCertTable, 1.1100 + (PKIX_PL_Object *) cachedKeys, 1.1101 + plContext), 1.1102 + PKIX_HASHTABLEREMOVEFAILED); 1.1103 + } 1.1104 + 1.1105 + } 1.1106 + 1.1107 +cleanup: 1.1108 + 1.1109 + PKIX_DECREF(subject); 1.1110 + PKIX_DECREF(certSel); 1.1111 + PKIX_DECREF(cachedKeys); 1.1112 + PKIX_DECREF(cachedValues); 1.1113 + PKIX_DECREF(cacheValidUntilDate); 1.1114 + PKIX_DECREF(cert); 1.1115 + PKIX_DECREF(cachedCertList); 1.1116 + PKIX_DECREF(selCertList); 1.1117 + PKIX_DECREF(invalidAfterDate); 1.1118 + PKIX_DECREF(cachedCertError); 1.1119 + PKIX_DECREF(selectorError); 1.1120 + 1.1121 + PKIX_RETURN(BUILD); 1.1122 +} 1.1123 + 1.1124 +/* 1.1125 + * FUNCTION: pkix_CacheCert_Add 1.1126 + * DESCRIPTION: 1.1127 + * 1.1128 + * Add Cert Hash Table for a cached item based on "store" and Subject in 1.1129 + * "certSelParams" as the hash keys and have "certs" as the key value. 1.1130 + * This hashtable is maintained in the following ways: 1.1131 + * 1) When creating the hashtable, maximum bucket size can be specified (0 for 1.1132 + * unlimited). If items in a bucket reaches its full size, an new addition 1.1133 + * will trigger the removal of the old as FIFO sequence. 1.1134 + * 2) A PKIX_PL_Date created with current time offset by constant 1.1135 + * CACHE_ITEM_PERIOD_SECONDS is attached to each item in the Hash Table. 1.1136 + * If the CertStore this Cert is from is a trusted one, the cache period is 1.1137 + * shorter so cache can be updated more frequently. 1.1138 + * When an item is retrieved, this date is compared against "testDate" for 1.1139 + * validity. If comparison indicates this item is expired, the item is 1.1140 + * removed from the bucket. 1.1141 + * 1.1142 + * PARAMETERS: 1.1143 + * "store" 1.1144 + * Address of CertStore as key to retrieve this CertChain. Must be 1.1145 + * non-NULL. 1.1146 + * "certSelParams" 1.1147 + * Address of ComCertSelParams that its subject is used as key to retrieve 1.1148 + * this CertChain. Must be non-NULL. 1.1149 + * "certs" 1.1150 + * Address PKIX_List of Certs will be stored. Must be no-NULL. 1.1151 + * "plContext" 1.1152 + * Platform-specific context pointer. 1.1153 + * THREAD SAFETY: 1.1154 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.1155 + * RETURNS: 1.1156 + * Returns NULL if the function succeeds. 1.1157 + * Returns an Error Error if the function fails in a non-fatal way. 1.1158 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.1159 + */ 1.1160 +PKIX_Error * 1.1161 +pkix_CacheCert_Add( 1.1162 + PKIX_CertStore *store, 1.1163 + PKIX_ComCertSelParams *certSelParams, 1.1164 + PKIX_List* certs, 1.1165 + void *plContext) 1.1166 +{ 1.1167 + PKIX_List *cachedKeys = NULL; 1.1168 + PKIX_List *cachedValues = NULL; 1.1169 + PKIX_PL_Date *cacheValidUntilDate = NULL; 1.1170 + PKIX_PL_X500Name *subject = NULL; 1.1171 + PKIX_Error *cachedCertError = NULL; 1.1172 + PKIX_CertStore_CheckTrustCallback trustCallback = NULL; 1.1173 + PKIX_UInt32 cachePeriod = CACHE_ITEM_PERIOD_SECONDS; 1.1174 + PKIX_UInt32 numCerts = 0; 1.1175 + 1.1176 + PKIX_ENTER(BUILD, "pkix_CacheCert_Add"); 1.1177 + PKIX_NULLCHECK_THREE(store, certSelParams, certs); 1.1178 + 1.1179 + PKIX_CHECK(PKIX_List_GetLength(certs, &numCerts, 1.1180 + plContext), 1.1181 + PKIX_LISTGETLENGTHFAILED); 1.1182 + if (numCerts == 0) { 1.1183 + /* Don't want to add an empty list. */ 1.1184 + goto cleanup; 1.1185 + } 1.1186 + 1.1187 + PKIX_CHECK(PKIX_List_Create(&cachedKeys, plContext), 1.1188 + PKIX_LISTCREATEFAILED); 1.1189 + 1.1190 + PKIX_CHECK(PKIX_List_AppendItem 1.1191 + (cachedKeys, (PKIX_PL_Object *)store, plContext), 1.1192 + PKIX_LISTAPPENDITEMFAILED); 1.1193 + 1.1194 + PKIX_CHECK(PKIX_ComCertSelParams_GetSubject 1.1195 + (certSelParams, &subject, plContext), 1.1196 + PKIX_COMCERTSELPARAMSGETSUBJECTFAILED); 1.1197 + 1.1198 + PKIX_NULLCHECK_ONE(subject); 1.1199 + 1.1200 + PKIX_CHECK(PKIX_List_AppendItem 1.1201 + (cachedKeys, (PKIX_PL_Object *)subject, plContext), 1.1202 + PKIX_LISTAPPENDITEMFAILED); 1.1203 + 1.1204 + PKIX_CHECK(PKIX_List_Create(&cachedValues, plContext), 1.1205 + PKIX_LISTCREATEFAILED); 1.1206 + 1.1207 + PKIX_CHECK(PKIX_CertStore_GetTrustCallback 1.1208 + (store, &trustCallback, plContext), 1.1209 + PKIX_CERTSTOREGETTRUSTCALLBACKFAILED); 1.1210 + 1.1211 + if (trustCallback) { 1.1212 + cachePeriod = CACHE_TRUST_ITEM_PERIOD_SECONDS; 1.1213 + } 1.1214 + 1.1215 + PKIX_CHECK(PKIX_PL_Date_Create_CurrentOffBySeconds 1.1216 + (cachePeriod, &cacheValidUntilDate, plContext), 1.1217 + PKIX_DATECREATECURRENTOFFBYSECONDSFAILED); 1.1218 + 1.1219 + PKIX_CHECK(PKIX_List_AppendItem 1.1220 + (cachedValues, 1.1221 + (PKIX_PL_Object *)cacheValidUntilDate, 1.1222 + plContext), 1.1223 + PKIX_LISTAPPENDITEMFAILED); 1.1224 + 1.1225 + PKIX_CHECK(PKIX_List_AppendItem 1.1226 + (cachedValues, 1.1227 + (PKIX_PL_Object *)certs, 1.1228 + plContext), 1.1229 + PKIX_LISTAPPENDITEMFAILED); 1.1230 + 1.1231 + cachedCertError = PKIX_PL_HashTable_Add 1.1232 + (cachedCertTable, 1.1233 + (PKIX_PL_Object *) cachedKeys, 1.1234 + (PKIX_PL_Object *) cachedValues, 1.1235 + plContext); 1.1236 + 1.1237 + pkix_cAddCount++; 1.1238 + 1.1239 + if (cachedCertError != NULL) { 1.1240 + PKIX_DEBUG("PKIX_PL_HashTable_Add for Certs skipped: " 1.1241 + "entry existed\n"); 1.1242 + } 1.1243 + 1.1244 +cleanup: 1.1245 + 1.1246 + PKIX_DECREF(subject); 1.1247 + PKIX_DECREF(cachedKeys); 1.1248 + PKIX_DECREF(cachedValues); 1.1249 + PKIX_DECREF(cacheValidUntilDate); 1.1250 + PKIX_DECREF(cachedCertError); 1.1251 + 1.1252 + PKIX_RETURN(BUILD); 1.1253 +} 1.1254 + 1.1255 +/* 1.1256 + * FUNCTION: pkix_CacheCrlEntry_Lookup 1.1257 + * DESCRIPTION: 1.1258 + * 1.1259 + * Look up CrlEntry Hash Table for a cached item based on "store", 1.1260 + * "certIssuer" and "certSerialNumber" as the hash keys and returns values 1.1261 + * "pCrls". If there isn't an item to match the key, a PKIX_FALSE is 1.1262 + * returned at "pFound". 1.1263 + * This hashtable is maintained in the following way: 1.1264 + * 1) When creating the hashtable, maximum bucket size can be specified (0 for 1.1265 + * unlimited). If items in a bucket reaches its full size, an new addition 1.1266 + * will trigger the removal of the old as FIFO sequence. 1.1267 + * 1.1268 + * PARAMETERS: 1.1269 + * "store" 1.1270 + * Address of CertStore as key to retrieve this CertChain. Must be 1.1271 + * non-NULL. 1.1272 + * "certIssuer" 1.1273 + * Address of X500Name that is used as key to retrieve the CRLEntries. 1.1274 + * Must be non-NULL. 1.1275 + * "certSerialNumber" 1.1276 + * Address of BigInt that is used as key to retrieve the CRLEntries. 1.1277 + * Must be non-NULL. 1.1278 + * "pFound" 1.1279 + * Address of KPKIX_Boolean indicating valid data is found. 1.1280 + * Must be non-NULL. 1.1281 + * "pCrls" 1.1282 + * Address PKIX_List where the CRLEntry will be stored. Must be no-NULL. 1.1283 + * "plContext" 1.1284 + * Platform-specific context pointer. 1.1285 + * THREAD SAFETY: 1.1286 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.1287 + * RETURNS: 1.1288 + * Returns NULL if the function succeeds. 1.1289 + * Returns an Error Error if the function fails in a non-fatal way. 1.1290 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.1291 + */ 1.1292 +PKIX_Error * 1.1293 +pkix_CacheCrlEntry_Lookup( 1.1294 + PKIX_CertStore *store, 1.1295 + PKIX_PL_X500Name *certIssuer, 1.1296 + PKIX_PL_BigInt *certSerialNumber, 1.1297 + PKIX_Boolean *pFound, 1.1298 + PKIX_List** pCrls, 1.1299 + void *plContext) 1.1300 +{ 1.1301 + PKIX_List *cachedKeys = NULL; 1.1302 + PKIX_List *cachedCrlEntryList = NULL; 1.1303 + PKIX_Error *cachedCrlEntryError = NULL; 1.1304 + 1.1305 + PKIX_ENTER(BUILD, "pkix_CacheCrlEntry_Lookup"); 1.1306 + PKIX_NULLCHECK_THREE(store, certIssuer, certSerialNumber); 1.1307 + PKIX_NULLCHECK_TWO(pFound, pCrls); 1.1308 + 1.1309 + *pFound = PKIX_FALSE; 1.1310 + 1.1311 + /* Find CrlEntry(s) by issuer and serial number */ 1.1312 + 1.1313 + PKIX_CHECK(PKIX_List_Create(&cachedKeys, plContext), 1.1314 + PKIX_LISTCREATEFAILED); 1.1315 + 1.1316 + PKIX_CHECK(PKIX_List_AppendItem 1.1317 + (cachedKeys, (PKIX_PL_Object *)store, plContext), 1.1318 + PKIX_LISTAPPENDITEMFAILED); 1.1319 + 1.1320 + PKIX_CHECK(PKIX_List_AppendItem 1.1321 + (cachedKeys, (PKIX_PL_Object *)certIssuer, plContext), 1.1322 + PKIX_LISTAPPENDITEMFAILED); 1.1323 + 1.1324 + PKIX_CHECK(PKIX_List_AppendItem 1.1325 + (cachedKeys, 1.1326 + (PKIX_PL_Object *)certSerialNumber, 1.1327 + plContext), 1.1328 + PKIX_LISTAPPENDITEMFAILED); 1.1329 + 1.1330 + cachedCrlEntryError = PKIX_PL_HashTable_Lookup 1.1331 + (cachedCrlEntryTable, 1.1332 + (PKIX_PL_Object *) cachedKeys, 1.1333 + (PKIX_PL_Object **) &cachedCrlEntryList, 1.1334 + plContext); 1.1335 + pkix_ceLookupCount++; 1.1336 + 1.1337 + /* 1.1338 + * We don't need check Date to invalidate this cache item, 1.1339 + * the item is uniquely defined and won't be reverted. Let 1.1340 + * the FIFO for cleaning up. 1.1341 + */ 1.1342 + 1.1343 + if (cachedCrlEntryList != NULL && cachedCrlEntryError == NULL ) { 1.1344 + 1.1345 + PKIX_INCREF(cachedCrlEntryList); 1.1346 + *pCrls = cachedCrlEntryList; 1.1347 + 1.1348 + *pFound = PKIX_TRUE; 1.1349 + 1.1350 + } else { 1.1351 + 1.1352 + *pFound = PKIX_FALSE; 1.1353 + } 1.1354 + 1.1355 +cleanup: 1.1356 + 1.1357 + PKIX_DECREF(cachedKeys); 1.1358 + PKIX_DECREF(cachedCrlEntryList); 1.1359 + PKIX_DECREF(cachedCrlEntryError); 1.1360 + 1.1361 + PKIX_RETURN(BUILD); 1.1362 +} 1.1363 + 1.1364 +/* 1.1365 + * FUNCTION: pkix_CacheCrlEntry_Add 1.1366 + * DESCRIPTION: 1.1367 + * 1.1368 + * Look up CrlEntry Hash Table for a cached item based on "store", 1.1369 + * "certIssuer" and "certSerialNumber" as the hash keys and have "pCrls" as 1.1370 + * the hash value. If there isn't an item to match the key, a PKIX_FALSE is 1.1371 + * returned at "pFound". 1.1372 + * This hashtable is maintained in the following way: 1.1373 + * 1) When creating the hashtable, maximum bucket size can be specified (0 for 1.1374 + * unlimited). If items in a bucket reaches its full size, an new addition 1.1375 + * will trigger the removal of the old as FIFO sequence. 1.1376 + * 1.1377 + * PARAMETERS: 1.1378 + * "store" 1.1379 + * Address of CertStore as key to retrieve this CertChain. Must be 1.1380 + * non-NULL. 1.1381 + * "certIssuer" 1.1382 + * Address of X500Name that is used as key to retrieve the CRLEntries. 1.1383 + * Must be non-NULL. 1.1384 + * "certSerialNumber" 1.1385 + * Address of BigInt that is used as key to retrieve the CRLEntries. 1.1386 + * Must be non-NULL. 1.1387 + * "crls" 1.1388 + * Address PKIX_List where the CRLEntry is stored. Must be no-NULL. 1.1389 + * "plContext" 1.1390 + * Platform-specific context pointer. 1.1391 + * THREAD SAFETY: 1.1392 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.1393 + * RETURNS: 1.1394 + * Returns NULL if the function succeeds. 1.1395 + * Returns an Error Error if the function fails in a non-fatal way. 1.1396 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.1397 + */ 1.1398 +PKIX_Error * 1.1399 +pkix_CacheCrlEntry_Add( 1.1400 + PKIX_CertStore *store, 1.1401 + PKIX_PL_X500Name *certIssuer, 1.1402 + PKIX_PL_BigInt *certSerialNumber, 1.1403 + PKIX_List* crls, 1.1404 + void *plContext) 1.1405 +{ 1.1406 + PKIX_List *cachedKeys = NULL; 1.1407 + PKIX_Error *cachedCrlEntryError = NULL; 1.1408 + 1.1409 + PKIX_ENTER(BUILD, "pkix_CacheCrlEntry_Add"); 1.1410 + PKIX_NULLCHECK_THREE(store, certIssuer, certSerialNumber); 1.1411 + PKIX_NULLCHECK_ONE(crls); 1.1412 + 1.1413 + /* Add CrlEntry(s) by issuer and serial number */ 1.1414 + 1.1415 + PKIX_CHECK(PKIX_List_Create(&cachedKeys, plContext), 1.1416 + PKIX_LISTCREATEFAILED); 1.1417 + 1.1418 + PKIX_CHECK(PKIX_List_AppendItem 1.1419 + (cachedKeys, (PKIX_PL_Object *)store, plContext), 1.1420 + PKIX_LISTAPPENDITEMFAILED); 1.1421 + 1.1422 + PKIX_CHECK(PKIX_List_AppendItem 1.1423 + (cachedKeys, (PKIX_PL_Object *)certIssuer, plContext), 1.1424 + PKIX_LISTAPPENDITEMFAILED); 1.1425 + 1.1426 + PKIX_CHECK(PKIX_List_AppendItem 1.1427 + (cachedKeys, 1.1428 + (PKIX_PL_Object *)certSerialNumber, 1.1429 + plContext), 1.1430 + PKIX_LISTAPPENDITEMFAILED); 1.1431 + 1.1432 + cachedCrlEntryError = PKIX_PL_HashTable_Add 1.1433 + (cachedCrlEntryTable, 1.1434 + (PKIX_PL_Object *) cachedKeys, 1.1435 + (PKIX_PL_Object *) crls, 1.1436 + plContext); 1.1437 + pkix_ceAddCount++; 1.1438 + 1.1439 +cleanup: 1.1440 + 1.1441 + PKIX_DECREF(cachedKeys); 1.1442 + PKIX_DECREF(cachedCrlEntryError); 1.1443 + 1.1444 + PKIX_RETURN(BUILD); 1.1445 +} 1.1446 + 1.1447 +#ifdef PKIX_OBJECT_LEAK_TEST 1.1448 + 1.1449 +/* TEST_START_FN and testStartFnStackPosition define at what state 1.1450 + * of the stack the object leak testing should begin. The condition 1.1451 + * in pkix_CheckForGeneratedError works the following way: do leak 1.1452 + * testing if at position testStartFnStackPosition in stack array 1.1453 + * (fnStackNameArr) we have called function TEST_START_FN. 1.1454 + * Note, that stack array get filled only when executing libpkix 1.1455 + * functions. 1.1456 + * */ 1.1457 +#define TEST_START_FN "PKIX_BuildChain" 1.1458 + 1.1459 +PKIX_Error* 1.1460 +pkix_CheckForGeneratedError(PKIX_StdVars * stdVars, 1.1461 + PKIX_ERRORCLASS errClass, 1.1462 + char * fnName, 1.1463 + PKIX_Boolean *errSetFlag, 1.1464 + void * plContext) 1.1465 +{ 1.1466 + PKIX_Error *genErr = NULL; 1.1467 + PKIX_UInt32 pos = 0; 1.1468 + PKIX_UInt32 strLen = 0; 1.1469 + 1.1470 + if (fnName) { 1.1471 + if (fnStackNameArr[testStartFnStackPosition] == NULL || 1.1472 + strcmp(fnStackNameArr[testStartFnStackPosition], TEST_START_FN) 1.1473 + ) { 1.1474 + /* return with out error if not with in boundary */ 1.1475 + return NULL; 1.1476 + } 1.1477 + if (!strcmp(fnName, TEST_START_FN)) { 1.1478 + *errSetFlag = PKIX_TRUE; 1.1479 + noErrorState = PKIX_FALSE; 1.1480 + errorGenerated = PKIX_FALSE; 1.1481 + } 1.1482 + } 1.1483 + 1.1484 + if (noErrorState || errorGenerated) return NULL; 1.1485 + 1.1486 + if (fnName && ( 1.1487 + !strcmp(fnName, "PKIX_PL_Object_DecRef") || 1.1488 + !strcmp(fnName, "PKIX_PL_Object_Unlock") || 1.1489 + !strcmp(fnName, "pkix_UnlockObject") || 1.1490 + !strcmp(fnName, "pkix_Throw") || 1.1491 + !strcmp(fnName, "pkix_trace_dump_cert") || 1.1492 + !strcmp(fnName, "PKIX_PL_Free"))) { 1.1493 + /* do not generate error for this functions */ 1.1494 + noErrorState = PKIX_TRUE; 1.1495 + *errSetFlag = PKIX_TRUE; 1.1496 + return NULL; 1.1497 + } 1.1498 + 1.1499 + if (PL_HashTableLookup(fnInvTable, &fnStackInvCountArr[stackPosition - 1])) { 1.1500 + return NULL; 1.1501 + } 1.1502 + 1.1503 + PL_HashTableAdd(fnInvTable, &fnStackInvCountArr[stackPosition - 1], nonNullValue); 1.1504 + errorGenerated = PKIX_TRUE; 1.1505 + noErrorState = PKIX_TRUE; 1.1506 + genErr = PKIX_DoThrow(stdVars, errClass, PKIX_MEMLEAKGENERATEDERROR, 1.1507 + errClass, plContext); 1.1508 + while(fnStackNameArr[pos]) { 1.1509 + strLen += PORT_Strlen(fnStackNameArr[pos++]) + 1; 1.1510 + } 1.1511 + strLen += 1; /* end of line. */ 1.1512 + pos = 0; 1.1513 + errorFnStackString = PORT_ZAlloc(strLen); 1.1514 + while(fnStackNameArr[pos]) { 1.1515 + strcat(errorFnStackString, "/"); 1.1516 + strcat(errorFnStackString, fnStackNameArr[pos++]); 1.1517 + } 1.1518 + noErrorState = PKIX_FALSE; 1.1519 + 1.1520 + return genErr; 1.1521 +} 1.1522 +#endif /* PKIX_OBJECT_LEAK_TEST */