1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/libpkix/pkix/checker/pkix_revocationchecker.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,467 @@ 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_revocationchecker.c 1.9 + * 1.10 + * RevocationChecker Object Functions 1.11 + * 1.12 + */ 1.13 + 1.14 +#include "pkix_revocationchecker.h" 1.15 +#include "pkix_tools.h" 1.16 + 1.17 +/* --Private-Functions-------------------------------------------- */ 1.18 + 1.19 +/* 1.20 + * FUNCTION: pkix_RevocationChecker_Destroy 1.21 + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) 1.22 + */ 1.23 +static PKIX_Error * 1.24 +pkix_RevocationChecker_Destroy( 1.25 + PKIX_PL_Object *object, 1.26 + void *plContext) 1.27 +{ 1.28 + PKIX_RevocationChecker *checker = NULL; 1.29 + 1.30 + PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_Destroy"); 1.31 + PKIX_NULLCHECK_ONE(object); 1.32 + 1.33 + /* Check that this object is a revocation checker */ 1.34 + PKIX_CHECK(pkix_CheckType 1.35 + (object, PKIX_REVOCATIONCHECKER_TYPE, plContext), 1.36 + PKIX_OBJECTNOTREVOCATIONCHECKER); 1.37 + 1.38 + checker = (PKIX_RevocationChecker *)object; 1.39 + 1.40 + PKIX_DECREF(checker->leafMethodList); 1.41 + PKIX_DECREF(checker->chainMethodList); 1.42 + 1.43 +cleanup: 1.44 + 1.45 + PKIX_RETURN(REVOCATIONCHECKER); 1.46 +} 1.47 + 1.48 +/* 1.49 + * FUNCTION: pkix_RevocationChecker_Duplicate 1.50 + * (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h) 1.51 + */ 1.52 +static PKIX_Error * 1.53 +pkix_RevocationChecker_Duplicate( 1.54 + PKIX_PL_Object *object, 1.55 + PKIX_PL_Object **pNewObject, 1.56 + void *plContext) 1.57 +{ 1.58 + PKIX_RevocationChecker *checker = NULL; 1.59 + PKIX_RevocationChecker *checkerDuplicate = NULL; 1.60 + PKIX_List *dupLeafList = NULL; 1.61 + PKIX_List *dupChainList = NULL; 1.62 + 1.63 + PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_Duplicate"); 1.64 + PKIX_NULLCHECK_TWO(object, pNewObject); 1.65 + 1.66 + PKIX_CHECK(pkix_CheckType 1.67 + (object, PKIX_REVOCATIONCHECKER_TYPE, plContext), 1.68 + PKIX_OBJECTNOTCERTCHAINCHECKER); 1.69 + 1.70 + checker = (PKIX_RevocationChecker *)object; 1.71 + 1.72 + if (checker->leafMethodList){ 1.73 + PKIX_CHECK(PKIX_PL_Object_Duplicate 1.74 + ((PKIX_PL_Object *)checker->leafMethodList, 1.75 + (PKIX_PL_Object **)&dupLeafList, 1.76 + plContext), 1.77 + PKIX_OBJECTDUPLICATEFAILED); 1.78 + } 1.79 + if (checker->chainMethodList){ 1.80 + PKIX_CHECK(PKIX_PL_Object_Duplicate 1.81 + ((PKIX_PL_Object *)checker->chainMethodList, 1.82 + (PKIX_PL_Object **)&dupChainList, 1.83 + plContext), 1.84 + PKIX_OBJECTDUPLICATEFAILED); 1.85 + } 1.86 + 1.87 + PKIX_CHECK( 1.88 + PKIX_RevocationChecker_Create(checker->leafMethodListFlags, 1.89 + checker->chainMethodListFlags, 1.90 + &checkerDuplicate, 1.91 + plContext), 1.92 + PKIX_REVOCATIONCHECKERCREATEFAILED); 1.93 + 1.94 + checkerDuplicate->leafMethodList = dupLeafList; 1.95 + checkerDuplicate->chainMethodList = dupChainList; 1.96 + dupLeafList = NULL; 1.97 + dupChainList = NULL; 1.98 + 1.99 + *pNewObject = (PKIX_PL_Object *)checkerDuplicate; 1.100 + 1.101 +cleanup: 1.102 + PKIX_DECREF(dupLeafList); 1.103 + PKIX_DECREF(dupChainList); 1.104 + 1.105 + PKIX_RETURN(REVOCATIONCHECKER); 1.106 +} 1.107 + 1.108 +/* 1.109 + * FUNCTION: pkix_RevocationChecker_RegisterSelf 1.110 + * DESCRIPTION: 1.111 + * Registers PKIX_REVOCATIONCHECKER_TYPE and its related functions with 1.112 + * systemClasses[] 1.113 + * THREAD SAFETY: 1.114 + * Not Thread Safe - for performance and complexity reasons 1.115 + * 1.116 + * Since this function is only called by PKIX_PL_Initialize, which should 1.117 + * only be called once, it is acceptable that this function is not 1.118 + * thread-safe. 1.119 + */ 1.120 +PKIX_Error * 1.121 +pkix_RevocationChecker_RegisterSelf(void *plContext) 1.122 +{ 1.123 + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; 1.124 + pkix_ClassTable_Entry entry; 1.125 + 1.126 + PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_RegisterSelf"); 1.127 + 1.128 + entry.description = "RevocationChecker"; 1.129 + entry.objCounter = 0; 1.130 + entry.typeObjectSize = sizeof(PKIX_RevocationChecker); 1.131 + entry.destructor = pkix_RevocationChecker_Destroy; 1.132 + entry.equalsFunction = NULL; 1.133 + entry.hashcodeFunction = NULL; 1.134 + entry.toStringFunction = NULL; 1.135 + entry.comparator = NULL; 1.136 + entry.duplicateFunction = pkix_RevocationChecker_Duplicate; 1.137 + 1.138 + systemClasses[PKIX_REVOCATIONCHECKER_TYPE] = entry; 1.139 + 1.140 + PKIX_RETURN(REVOCATIONCHECKER); 1.141 +} 1.142 + 1.143 +/* Sort methods by theirs priorities */ 1.144 +static PKIX_Error * 1.145 +pkix_RevocationChecker_SortComparator( 1.146 + PKIX_PL_Object *obj1, 1.147 + PKIX_PL_Object *obj2, 1.148 + PKIX_Int32 *pResult, 1.149 + void *plContext) 1.150 +{ 1.151 + pkix_RevocationMethod *method1 = NULL, *method2 = NULL; 1.152 + 1.153 + PKIX_ENTER(BUILD, "pkix_RevocationChecker_SortComparator"); 1.154 + 1.155 + method1 = (pkix_RevocationMethod *)obj1; 1.156 + method2 = (pkix_RevocationMethod *)obj2; 1.157 + 1.158 + *pResult = (method1->priority > method2->priority); 1.159 + 1.160 + PKIX_RETURN(BUILD); 1.161 +} 1.162 + 1.163 + 1.164 +/* --Public-Functions--------------------------------------------- */ 1.165 + 1.166 + 1.167 +/* 1.168 + * FUNCTION: PKIX_RevocationChecker_Create (see comments in pkix_revchecker.h) 1.169 + */ 1.170 +PKIX_Error * 1.171 +PKIX_RevocationChecker_Create( 1.172 + PKIX_UInt32 leafMethodListFlags, 1.173 + PKIX_UInt32 chainMethodListFlags, 1.174 + PKIX_RevocationChecker **pChecker, 1.175 + void *plContext) 1.176 +{ 1.177 + PKIX_RevocationChecker *checker = NULL; 1.178 + 1.179 + PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_Create"); 1.180 + PKIX_NULLCHECK_ONE(pChecker); 1.181 + 1.182 + PKIX_CHECK( 1.183 + PKIX_PL_Object_Alloc(PKIX_REVOCATIONCHECKER_TYPE, 1.184 + sizeof (PKIX_RevocationChecker), 1.185 + (PKIX_PL_Object **)&checker, 1.186 + plContext), 1.187 + PKIX_COULDNOTCREATECERTCHAINCHECKEROBJECT); 1.188 + 1.189 + checker->leafMethodListFlags = leafMethodListFlags; 1.190 + checker->chainMethodListFlags = chainMethodListFlags; 1.191 + checker->leafMethodList = NULL; 1.192 + checker->chainMethodList = NULL; 1.193 + 1.194 + *pChecker = checker; 1.195 + checker = NULL; 1.196 + 1.197 +cleanup: 1.198 + PKIX_DECREF(checker); 1.199 + 1.200 + PKIX_RETURN(REVOCATIONCHECKER); 1.201 +} 1.202 + 1.203 +/* 1.204 + * FUNCTION: PKIX_RevocationChecker_CreateAndAddMethod 1.205 + */ 1.206 +PKIX_Error * 1.207 +PKIX_RevocationChecker_CreateAndAddMethod( 1.208 + PKIX_RevocationChecker *revChecker, 1.209 + PKIX_ProcessingParams *params, 1.210 + PKIX_RevocationMethodType methodType, 1.211 + PKIX_UInt32 flags, 1.212 + PKIX_UInt32 priority, 1.213 + PKIX_PL_VerifyCallback verificationFn, 1.214 + PKIX_Boolean isLeafMethod, 1.215 + void *plContext) 1.216 +{ 1.217 + PKIX_List **methodList = NULL; 1.218 + PKIX_List *unsortedList = NULL; 1.219 + PKIX_List *certStores = NULL; 1.220 + pkix_RevocationMethod *method = NULL; 1.221 + pkix_LocalRevocationCheckFn *localRevChecker = NULL; 1.222 + pkix_ExternalRevocationCheckFn *externRevChecker = NULL; 1.223 + PKIX_UInt32 miFlags; 1.224 + 1.225 + PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_CreateAndAddMethod"); 1.226 + PKIX_NULLCHECK_ONE(revChecker); 1.227 + 1.228 + /* If the caller has said "Either one is sufficient, then don't let the 1.229 + * absence of any one method's info lead to an overall failure. 1.230 + */ 1.231 + miFlags = isLeafMethod ? revChecker->leafMethodListFlags 1.232 + : revChecker->chainMethodListFlags; 1.233 + if (miFlags & PKIX_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE) 1.234 + flags &= ~PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO; 1.235 + 1.236 + switch (methodType) { 1.237 + case PKIX_RevocationMethod_CRL: 1.238 + localRevChecker = pkix_CrlChecker_CheckLocal; 1.239 + externRevChecker = pkix_CrlChecker_CheckExternal; 1.240 + PKIX_CHECK( 1.241 + PKIX_ProcessingParams_GetCertStores(params, &certStores, 1.242 + plContext), 1.243 + PKIX_PROCESSINGPARAMSGETCERTSTORESFAILED); 1.244 + PKIX_CHECK( 1.245 + pkix_CrlChecker_Create(methodType, flags, priority, 1.246 + localRevChecker, externRevChecker, 1.247 + certStores, verificationFn, 1.248 + &method, 1.249 + plContext), 1.250 + PKIX_COULDNOTCREATECRLCHECKEROBJECT); 1.251 + break; 1.252 + case PKIX_RevocationMethod_OCSP: 1.253 + localRevChecker = pkix_OcspChecker_CheckLocal; 1.254 + externRevChecker = pkix_OcspChecker_CheckExternal; 1.255 + PKIX_CHECK( 1.256 + pkix_OcspChecker_Create(methodType, flags, priority, 1.257 + localRevChecker, externRevChecker, 1.258 + verificationFn, 1.259 + &method, 1.260 + plContext), 1.261 + PKIX_COULDNOTCREATEOCSPCHECKEROBJECT); 1.262 + break; 1.263 + default: 1.264 + PKIX_ERROR(PKIX_INVALIDREVOCATIONMETHOD); 1.265 + } 1.266 + 1.267 + if (isLeafMethod) { 1.268 + methodList = &revChecker->leafMethodList; 1.269 + } else { 1.270 + methodList = &revChecker->chainMethodList; 1.271 + } 1.272 + 1.273 + if (*methodList == NULL) { 1.274 + PKIX_CHECK( 1.275 + PKIX_List_Create(methodList, plContext), 1.276 + PKIX_LISTCREATEFAILED); 1.277 + } 1.278 + unsortedList = *methodList; 1.279 + PKIX_CHECK( 1.280 + PKIX_List_AppendItem(unsortedList, (PKIX_PL_Object*)method, plContext), 1.281 + PKIX_LISTAPPENDITEMFAILED); 1.282 + PKIX_CHECK( 1.283 + pkix_List_BubbleSort(unsortedList, 1.284 + pkix_RevocationChecker_SortComparator, 1.285 + methodList, plContext), 1.286 + PKIX_LISTBUBBLESORTFAILED); 1.287 + 1.288 +cleanup: 1.289 + PKIX_DECREF(method); 1.290 + PKIX_DECREF(unsortedList); 1.291 + PKIX_DECREF(certStores); 1.292 + 1.293 + PKIX_RETURN(REVOCATIONCHECKER); 1.294 +} 1.295 + 1.296 +/* 1.297 + * FUNCTION: PKIX_RevocationChecker_Check 1.298 + */ 1.299 +PKIX_Error * 1.300 +PKIX_RevocationChecker_Check( 1.301 + PKIX_PL_Cert *cert, 1.302 + PKIX_PL_Cert *issuer, 1.303 + PKIX_RevocationChecker *revChecker, 1.304 + PKIX_ProcessingParams *procParams, 1.305 + PKIX_Boolean chainVerificationState, 1.306 + PKIX_Boolean testingLeafCert, 1.307 + PKIX_RevocationStatus *pRevStatus, 1.308 + PKIX_UInt32 *pReasonCode, 1.309 + void **pNbioContext, 1.310 + void *plContext) 1.311 +{ 1.312 + PKIX_RevocationStatus overallStatus = PKIX_RevStatus_NoInfo; 1.313 + PKIX_RevocationStatus methodStatus[PKIX_RevocationMethod_MAX]; 1.314 + PKIX_Boolean onlyUseRemoteMethods = PKIX_FALSE; 1.315 + PKIX_UInt32 revFlags = 0; 1.316 + PKIX_List *revList = NULL; 1.317 + PKIX_PL_Date *date = NULL; 1.318 + pkix_RevocationMethod *method = NULL; 1.319 + void *nbioContext; 1.320 + int tries; 1.321 + 1.322 + PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_Check"); 1.323 + PKIX_NULLCHECK_TWO(revChecker, procParams); 1.324 + 1.325 + nbioContext = *pNbioContext; 1.326 + *pNbioContext = NULL; 1.327 + 1.328 + if (testingLeafCert) { 1.329 + revList = revChecker->leafMethodList; 1.330 + revFlags = revChecker->leafMethodListFlags; 1.331 + } else { 1.332 + revList = revChecker->chainMethodList; 1.333 + revFlags = revChecker->chainMethodListFlags; 1.334 + } 1.335 + if (!revList) { 1.336 + /* Return NoInfo status */ 1.337 + goto cleanup; 1.338 + } 1.339 + 1.340 + PORT_Memset(methodStatus, PKIX_RevStatus_NoInfo, 1.341 + sizeof(PKIX_RevocationStatus) * PKIX_RevocationMethod_MAX); 1.342 + 1.343 + date = procParams->date; 1.344 + 1.345 + /* Need to have two loops if we testing all local info first: 1.346 + * first we are going to test all local(cached) info 1.347 + * second, all remote info(fetching) */ 1.348 + for (tries = 0;tries < 2;tries++) { 1.349 + int methodNum = 0; 1.350 + for (;methodNum < revList->length;methodNum++) { 1.351 + PKIX_UInt32 methodFlags = 0; 1.352 + 1.353 + PKIX_DECREF(method); 1.354 + PKIX_CHECK( 1.355 + PKIX_List_GetItem(revList, methodNum, 1.356 + (PKIX_PL_Object**)&method, plContext), 1.357 + PKIX_LISTGETITEMFAILED); 1.358 + methodFlags = method->flags; 1.359 + if (!(methodFlags & PKIX_REV_M_TEST_USING_THIS_METHOD)) { 1.360 + /* Will not check with this method. Skipping... */ 1.361 + continue; 1.362 + } 1.363 + if (!onlyUseRemoteMethods && 1.364 + methodStatus[methodNum] == PKIX_RevStatus_NoInfo) { 1.365 + PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; 1.366 + PKIX_CHECK_NO_GOTO( 1.367 + (*method->localRevChecker)(cert, issuer, date, 1.368 + method, procParams, 1.369 + methodFlags, 1.370 + chainVerificationState, 1.371 + &revStatus, 1.372 + pReasonCode, plContext), 1.373 + PKIX_REVCHECKERCHECKFAILED); 1.374 + methodStatus[methodNum] = revStatus; 1.375 + if (revStatus == PKIX_RevStatus_Revoked) { 1.376 + /* if error was generated use it as final error. */ 1.377 + overallStatus = PKIX_RevStatus_Revoked; 1.378 + goto cleanup; 1.379 + } 1.380 + if (pkixErrorResult) { 1.381 + /* Disregard errors. Only returned revStatus matters. */ 1.382 + PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult, 1.383 + plContext); 1.384 + pkixErrorResult = NULL; 1.385 + } 1.386 + } 1.387 + if ((!(revFlags & PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST) || 1.388 + onlyUseRemoteMethods) && 1.389 + chainVerificationState && 1.390 + methodStatus[methodNum] == PKIX_RevStatus_NoInfo) { 1.391 + if (!(methodFlags & PKIX_REV_M_FORBID_NETWORK_FETCHING)) { 1.392 + PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; 1.393 + PKIX_CHECK_NO_GOTO( 1.394 + (*method->externalRevChecker)(cert, issuer, date, 1.395 + method, 1.396 + procParams, methodFlags, 1.397 + &revStatus, pReasonCode, 1.398 + &nbioContext, plContext), 1.399 + PKIX_REVCHECKERCHECKFAILED); 1.400 + methodStatus[methodNum] = revStatus; 1.401 + if (revStatus == PKIX_RevStatus_Revoked) { 1.402 + /* if error was generated use it as final error. */ 1.403 + overallStatus = PKIX_RevStatus_Revoked; 1.404 + goto cleanup; 1.405 + } 1.406 + if (pkixErrorResult) { 1.407 + /* Disregard errors. Only returned revStatus matters. */ 1.408 + PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult, 1.409 + plContext); 1.410 + pkixErrorResult = NULL; 1.411 + } 1.412 + } else if (methodFlags & 1.413 + PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) { 1.414 + /* Info is not in the local cache. Network fetching is not 1.415 + * allowed. If need to fail on missing fresh info for the 1.416 + * the method, then we should fail right here.*/ 1.417 + overallStatus = PKIX_RevStatus_Revoked; 1.418 + goto cleanup; 1.419 + } 1.420 + } 1.421 + /* If success and we should not check the next method, then 1.422 + * return a success. */ 1.423 + if (methodStatus[methodNum] == PKIX_RevStatus_Success && 1.424 + !(methodFlags & PKIX_REV_M_CONTINUE_TESTING_ON_FRESH_INFO)) { 1.425 + overallStatus = PKIX_RevStatus_Success; 1.426 + goto cleanup; 1.427 + } 1.428 + } /* inner loop */ 1.429 + if (!onlyUseRemoteMethods && 1.430 + revFlags & PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST && 1.431 + chainVerificationState) { 1.432 + onlyUseRemoteMethods = PKIX_TRUE; 1.433 + continue; 1.434 + } 1.435 + break; 1.436 + } /* outer loop */ 1.437 + 1.438 + if (overallStatus == PKIX_RevStatus_NoInfo && 1.439 + chainVerificationState) { 1.440 + /* The following check makes sence only for chain 1.441 + * validation step, sinse we do not fetch info while 1.442 + * in the process of finding trusted anchor. 1.443 + * For chain building step it is enough to know, that 1.444 + * the cert was not directly revoked by any of the 1.445 + * methods. */ 1.446 + 1.447 + /* Still have no info. But one of the method could 1.448 + * have returned success status(possible if CONTINUE 1.449 + * TESTING ON FRESH INFO flag was used). 1.450 + * If any of the methods have returned Success status, 1.451 + * the overallStatus should be success. */ 1.452 + int methodNum = 0; 1.453 + for (;methodNum < PKIX_RevocationMethod_MAX;methodNum++) { 1.454 + if (methodStatus[methodNum] == PKIX_RevStatus_Success) { 1.455 + overallStatus = PKIX_RevStatus_Success; 1.456 + goto cleanup; 1.457 + } 1.458 + } 1.459 + if (revFlags & PKIX_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE) { 1.460 + overallStatus = PKIX_RevStatus_Revoked; 1.461 + } 1.462 + } 1.463 + 1.464 +cleanup: 1.465 + *pRevStatus = overallStatus; 1.466 + PKIX_DECREF(method); 1.467 + 1.468 + PKIX_RETURN(REVOCATIONCHECKER); 1.469 +} 1.470 +