| OLD | NEW |
| (Empty) |
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 4 /* | |
| 5 * pkix_revocationchecker.c | |
| 6 * | |
| 7 * RevocationChecker Object Functions | |
| 8 * | |
| 9 */ | |
| 10 | |
| 11 #include "pkix_revocationchecker.h" | |
| 12 #include "pkix_tools.h" | |
| 13 | |
| 14 /* --Private-Functions-------------------------------------------- */ | |
| 15 | |
| 16 /* | |
| 17 * FUNCTION: pkix_RevocationChecker_Destroy | |
| 18 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) | |
| 19 */ | |
| 20 static PKIX_Error * | |
| 21 pkix_RevocationChecker_Destroy( | |
| 22 PKIX_PL_Object *object, | |
| 23 void *plContext) | |
| 24 { | |
| 25 PKIX_RevocationChecker *checker = NULL; | |
| 26 | |
| 27 PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_Destroy"); | |
| 28 PKIX_NULLCHECK_ONE(object); | |
| 29 | |
| 30 /* Check that this object is a revocation checker */ | |
| 31 PKIX_CHECK(pkix_CheckType | |
| 32 (object, PKIX_REVOCATIONCHECKER_TYPE, plContext), | |
| 33 PKIX_OBJECTNOTREVOCATIONCHECKER); | |
| 34 | |
| 35 checker = (PKIX_RevocationChecker *)object; | |
| 36 | |
| 37 PKIX_DECREF(checker->leafMethodList); | |
| 38 PKIX_DECREF(checker->chainMethodList); | |
| 39 | |
| 40 cleanup: | |
| 41 | |
| 42 PKIX_RETURN(REVOCATIONCHECKER); | |
| 43 } | |
| 44 | |
| 45 /* | |
| 46 * FUNCTION: pkix_RevocationChecker_Duplicate | |
| 47 * (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h) | |
| 48 */ | |
| 49 static PKIX_Error * | |
| 50 pkix_RevocationChecker_Duplicate( | |
| 51 PKIX_PL_Object *object, | |
| 52 PKIX_PL_Object **pNewObject, | |
| 53 void *plContext) | |
| 54 { | |
| 55 PKIX_RevocationChecker *checker = NULL; | |
| 56 PKIX_RevocationChecker *checkerDuplicate = NULL; | |
| 57 PKIX_List *dupLeafList = NULL; | |
| 58 PKIX_List *dupChainList = NULL; | |
| 59 | |
| 60 PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_Duplicate"); | |
| 61 PKIX_NULLCHECK_TWO(object, pNewObject); | |
| 62 | |
| 63 PKIX_CHECK(pkix_CheckType | |
| 64 (object, PKIX_REVOCATIONCHECKER_TYPE, plContext), | |
| 65 PKIX_OBJECTNOTCERTCHAINCHECKER); | |
| 66 | |
| 67 checker = (PKIX_RevocationChecker *)object; | |
| 68 | |
| 69 if (checker->leafMethodList){ | |
| 70 PKIX_CHECK(PKIX_PL_Object_Duplicate | |
| 71 ((PKIX_PL_Object *)checker->leafMethodList, | |
| 72 (PKIX_PL_Object **)&dupLeafList, | |
| 73 plContext), | |
| 74 PKIX_OBJECTDUPLICATEFAILED); | |
| 75 } | |
| 76 if (checker->chainMethodList){ | |
| 77 PKIX_CHECK(PKIX_PL_Object_Duplicate | |
| 78 ((PKIX_PL_Object *)checker->chainMethodList, | |
| 79 (PKIX_PL_Object **)&dupChainList, | |
| 80 plContext), | |
| 81 PKIX_OBJECTDUPLICATEFAILED); | |
| 82 } | |
| 83 | |
| 84 PKIX_CHECK( | |
| 85 PKIX_RevocationChecker_Create(checker->leafMethodListFlags, | |
| 86 checker->chainMethodListFlags, | |
| 87 &checkerDuplicate, | |
| 88 plContext), | |
| 89 PKIX_REVOCATIONCHECKERCREATEFAILED); | |
| 90 | |
| 91 checkerDuplicate->leafMethodList = dupLeafList; | |
| 92 checkerDuplicate->chainMethodList = dupChainList; | |
| 93 dupLeafList = NULL; | |
| 94 dupChainList = NULL; | |
| 95 | |
| 96 *pNewObject = (PKIX_PL_Object *)checkerDuplicate; | |
| 97 | |
| 98 cleanup: | |
| 99 PKIX_DECREF(dupLeafList); | |
| 100 PKIX_DECREF(dupChainList); | |
| 101 | |
| 102 PKIX_RETURN(REVOCATIONCHECKER); | |
| 103 } | |
| 104 | |
| 105 /* | |
| 106 * FUNCTION: pkix_RevocationChecker_RegisterSelf | |
| 107 * DESCRIPTION: | |
| 108 * Registers PKIX_REVOCATIONCHECKER_TYPE and its related functions with | |
| 109 * systemClasses[] | |
| 110 * THREAD SAFETY: | |
| 111 * Not Thread Safe - for performance and complexity reasons | |
| 112 * | |
| 113 * Since this function is only called by PKIX_PL_Initialize, which should | |
| 114 * only be called once, it is acceptable that this function is not | |
| 115 * thread-safe. | |
| 116 */ | |
| 117 PKIX_Error * | |
| 118 pkix_RevocationChecker_RegisterSelf(void *plContext) | |
| 119 { | |
| 120 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; | |
| 121 pkix_ClassTable_Entry entry; | |
| 122 | |
| 123 PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_RegisterSelf"); | |
| 124 | |
| 125 entry.description = "RevocationChecker"; | |
| 126 entry.objCounter = 0; | |
| 127 entry.typeObjectSize = sizeof(PKIX_RevocationChecker); | |
| 128 entry.destructor = pkix_RevocationChecker_Destroy; | |
| 129 entry.equalsFunction = NULL; | |
| 130 entry.hashcodeFunction = NULL; | |
| 131 entry.toStringFunction = NULL; | |
| 132 entry.comparator = NULL; | |
| 133 entry.duplicateFunction = pkix_RevocationChecker_Duplicate; | |
| 134 | |
| 135 systemClasses[PKIX_REVOCATIONCHECKER_TYPE] = entry; | |
| 136 | |
| 137 PKIX_RETURN(REVOCATIONCHECKER); | |
| 138 } | |
| 139 | |
| 140 /* Sort methods by their priorities (lower priority = higher preference) */ | |
| 141 static PKIX_Error * | |
| 142 pkix_RevocationChecker_SortComparator( | |
| 143 PKIX_PL_Object *obj1, | |
| 144 PKIX_PL_Object *obj2, | |
| 145 PKIX_Int32 *pResult, | |
| 146 void *plContext) | |
| 147 { | |
| 148 pkix_RevocationMethod *method1 = NULL, *method2 = NULL; | |
| 149 | |
| 150 PKIX_ENTER(BUILD, "pkix_RevocationChecker_SortComparator"); | |
| 151 | |
| 152 method1 = (pkix_RevocationMethod *)obj1; | |
| 153 method2 = (pkix_RevocationMethod *)obj2; | |
| 154 | |
| 155 if (method1->priority < method2->priority) { | |
| 156 *pResult = -1; | |
| 157 } else if (method1->priority > method2->priority) { | |
| 158 *pResult = 1; | |
| 159 } else { | |
| 160 *pResult = 0; | |
| 161 } | |
| 162 | |
| 163 PKIX_RETURN(BUILD); | |
| 164 } | |
| 165 | |
| 166 | |
| 167 /* --Public-Functions--------------------------------------------- */ | |
| 168 | |
| 169 | |
| 170 /* | |
| 171 * FUNCTION: PKIX_RevocationChecker_Create (see comments in pkix_revchecker.h) | |
| 172 */ | |
| 173 PKIX_Error * | |
| 174 PKIX_RevocationChecker_Create( | |
| 175 PKIX_UInt32 leafMethodListFlags, | |
| 176 PKIX_UInt32 chainMethodListFlags, | |
| 177 PKIX_RevocationChecker **pChecker, | |
| 178 void *plContext) | |
| 179 { | |
| 180 PKIX_RevocationChecker *checker = NULL; | |
| 181 | |
| 182 PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_Create"); | |
| 183 PKIX_NULLCHECK_ONE(pChecker); | |
| 184 | |
| 185 PKIX_CHECK( | |
| 186 PKIX_PL_Object_Alloc(PKIX_REVOCATIONCHECKER_TYPE, | |
| 187 sizeof (PKIX_RevocationChecker), | |
| 188 (PKIX_PL_Object **)&checker, | |
| 189 plContext), | |
| 190 PKIX_COULDNOTCREATECERTCHAINCHECKEROBJECT); | |
| 191 | |
| 192 checker->leafMethodListFlags = leafMethodListFlags; | |
| 193 checker->chainMethodListFlags = chainMethodListFlags; | |
| 194 checker->leafMethodList = NULL; | |
| 195 checker->chainMethodList = NULL; | |
| 196 | |
| 197 *pChecker = checker; | |
| 198 checker = NULL; | |
| 199 | |
| 200 cleanup: | |
| 201 PKIX_DECREF(checker); | |
| 202 | |
| 203 PKIX_RETURN(REVOCATIONCHECKER); | |
| 204 } | |
| 205 | |
| 206 /* | |
| 207 * FUNCTION: PKIX_RevocationChecker_CreateAndAddMethod | |
| 208 */ | |
| 209 PKIX_Error * | |
| 210 PKIX_RevocationChecker_CreateAndAddMethod( | |
| 211 PKIX_RevocationChecker *revChecker, | |
| 212 PKIX_ProcessingParams *params, | |
| 213 PKIX_RevocationMethodType methodType, | |
| 214 PKIX_UInt32 flags, | |
| 215 PKIX_UInt32 priority, | |
| 216 PKIX_PL_VerifyCallback verificationFn, | |
| 217 PKIX_Boolean isLeafMethod, | |
| 218 void *plContext) | |
| 219 { | |
| 220 PKIX_List **methodList = NULL; | |
| 221 PKIX_List *unsortedList = NULL; | |
| 222 PKIX_List *certStores = NULL; | |
| 223 pkix_RevocationMethod *method = NULL; | |
| 224 pkix_LocalRevocationCheckFn *localRevChecker = NULL; | |
| 225 pkix_ExternalRevocationCheckFn *externRevChecker = NULL; | |
| 226 PKIX_UInt32 miFlags; | |
| 227 | |
| 228 PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_CreateAndAddMethod"); | |
| 229 PKIX_NULLCHECK_ONE(revChecker); | |
| 230 | |
| 231 /* If the caller has said "Either one is sufficient, then don't let the | |
| 232 * absence of any one method's info lead to an overall failure. | |
| 233 */ | |
| 234 miFlags = isLeafMethod ? revChecker->leafMethodListFlags | |
| 235 : revChecker->chainMethodListFlags; | |
| 236 if (miFlags & PKIX_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE) | |
| 237 flags &= ~PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO; | |
| 238 | |
| 239 switch (methodType) { | |
| 240 case PKIX_RevocationMethod_CRL: | |
| 241 localRevChecker = pkix_CrlChecker_CheckLocal; | |
| 242 externRevChecker = pkix_CrlChecker_CheckExternal; | |
| 243 PKIX_CHECK( | |
| 244 PKIX_ProcessingParams_GetCertStores(params, &certStores, | |
| 245 plContext), | |
| 246 PKIX_PROCESSINGPARAMSGETCERTSTORESFAILED); | |
| 247 PKIX_CHECK( | |
| 248 pkix_CrlChecker_Create(methodType, flags, priority, | |
| 249 localRevChecker, externRevChecker, | |
| 250 certStores, verificationFn, | |
| 251 &method, | |
| 252 plContext), | |
| 253 PKIX_COULDNOTCREATECRLCHECKEROBJECT); | |
| 254 break; | |
| 255 case PKIX_RevocationMethod_OCSP: | |
| 256 localRevChecker = pkix_OcspChecker_CheckLocal; | |
| 257 externRevChecker = pkix_OcspChecker_CheckExternal; | |
| 258 PKIX_CHECK( | |
| 259 pkix_OcspChecker_Create(methodType, flags, priority, | |
| 260 localRevChecker, externRevChecker, | |
| 261 verificationFn, | |
| 262 &method, | |
| 263 plContext), | |
| 264 PKIX_COULDNOTCREATEOCSPCHECKEROBJECT); | |
| 265 break; | |
| 266 default: | |
| 267 PKIX_ERROR(PKIX_INVALIDREVOCATIONMETHOD); | |
| 268 } | |
| 269 | |
| 270 if (isLeafMethod) { | |
| 271 methodList = &revChecker->leafMethodList; | |
| 272 } else { | |
| 273 methodList = &revChecker->chainMethodList; | |
| 274 } | |
| 275 | |
| 276 if (*methodList == NULL) { | |
| 277 PKIX_CHECK( | |
| 278 PKIX_List_Create(methodList, plContext), | |
| 279 PKIX_LISTCREATEFAILED); | |
| 280 } | |
| 281 unsortedList = *methodList; | |
| 282 PKIX_CHECK( | |
| 283 PKIX_List_AppendItem(unsortedList, (PKIX_PL_Object*)method, plContext), | |
| 284 PKIX_LISTAPPENDITEMFAILED); | |
| 285 PKIX_CHECK( | |
| 286 pkix_List_BubbleSort(unsortedList, | |
| 287 pkix_RevocationChecker_SortComparator, | |
| 288 methodList, plContext), | |
| 289 PKIX_LISTBUBBLESORTFAILED); | |
| 290 | |
| 291 cleanup: | |
| 292 PKIX_DECREF(method); | |
| 293 PKIX_DECREF(unsortedList); | |
| 294 PKIX_DECREF(certStores); | |
| 295 | |
| 296 PKIX_RETURN(REVOCATIONCHECKER); | |
| 297 } | |
| 298 | |
| 299 /* | |
| 300 * FUNCTION: PKIX_RevocationChecker_Check | |
| 301 */ | |
| 302 PKIX_Error * | |
| 303 PKIX_RevocationChecker_Check( | |
| 304 PKIX_PL_Cert *cert, | |
| 305 PKIX_PL_Cert *issuer, | |
| 306 PKIX_RevocationChecker *revChecker, | |
| 307 PKIX_ProcessingParams *procParams, | |
| 308 PKIX_Boolean chainVerificationState, | |
| 309 PKIX_Boolean testingLeafCert, | |
| 310 PKIX_RevocationStatus *pRevStatus, | |
| 311 PKIX_UInt32 *pReasonCode, | |
| 312 void **pNbioContext, | |
| 313 void *plContext) | |
| 314 { | |
| 315 PKIX_RevocationStatus overallStatus = PKIX_RevStatus_NoInfo; | |
| 316 PKIX_RevocationStatus methodStatus[PKIX_RevocationMethod_MAX]; | |
| 317 PKIX_Boolean onlyUseRemoteMethods = PKIX_FALSE; | |
| 318 PKIX_UInt32 revFlags = 0; | |
| 319 PKIX_List *revList = NULL; | |
| 320 PKIX_PL_Date *date = NULL; | |
| 321 pkix_RevocationMethod *method = NULL; | |
| 322 void *nbioContext; | |
| 323 int tries; | |
| 324 | |
| 325 PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_Check"); | |
| 326 PKIX_NULLCHECK_TWO(revChecker, procParams); | |
| 327 | |
| 328 nbioContext = *pNbioContext; | |
| 329 *pNbioContext = NULL; | |
| 330 | |
| 331 if (testingLeafCert) { | |
| 332 revList = revChecker->leafMethodList; | |
| 333 revFlags = revChecker->leafMethodListFlags; | |
| 334 } else { | |
| 335 revList = revChecker->chainMethodList; | |
| 336 revFlags = revChecker->chainMethodListFlags; | |
| 337 } | |
| 338 if (!revList) { | |
| 339 /* Return NoInfo status */ | |
| 340 goto cleanup; | |
| 341 } | |
| 342 | |
| 343 PORT_Memset(methodStatus, PKIX_RevStatus_NoInfo, | |
| 344 sizeof(PKIX_RevocationStatus) * PKIX_RevocationMethod_MAX); | |
| 345 | |
| 346 date = procParams->date; | |
| 347 | |
| 348 /* Need to have two loops if we testing all local info first: | |
| 349 * first we are going to test all local(cached) info | |
| 350 * second, all remote info(fetching) */ | |
| 351 for (tries = 0;tries < 2;tries++) { | |
| 352 unsigned int methodNum = 0; | |
| 353 for (;methodNum < revList->length;methodNum++) { | |
| 354 PKIX_UInt32 methodFlags = 0; | |
| 355 | |
| 356 PKIX_DECREF(method); | |
| 357 PKIX_CHECK( | |
| 358 PKIX_List_GetItem(revList, methodNum, | |
| 359 (PKIX_PL_Object**)&method, plContext), | |
| 360 PKIX_LISTGETITEMFAILED); | |
| 361 methodFlags = method->flags; | |
| 362 if (!(methodFlags & PKIX_REV_M_TEST_USING_THIS_METHOD)) { | |
| 363 /* Will not check with this method. Skipping... */ | |
| 364 continue; | |
| 365 } | |
| 366 if (!onlyUseRemoteMethods && | |
| 367 methodStatus[methodNum] == PKIX_RevStatus_NoInfo) { | |
| 368 PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; | |
| 369 PKIX_CHECK_NO_GOTO( | |
| 370 (*method->localRevChecker)(cert, issuer, date, | |
| 371 method, procParams, | |
| 372 methodFlags, | |
| 373 chainVerificationState, | |
| 374 &revStatus, | |
| 375 (CERTCRLEntryReasonCode *)pReason
Code, | |
| 376 plContext), | |
| 377 PKIX_REVCHECKERCHECKFAILED); | |
| 378 methodStatus[methodNum] = revStatus; | |
| 379 if (revStatus == PKIX_RevStatus_Revoked) { | |
| 380 /* if error was generated use it as final error. */ | |
| 381 overallStatus = PKIX_RevStatus_Revoked; | |
| 382 goto cleanup; | |
| 383 } | |
| 384 if (pkixErrorResult) { | |
| 385 /* Disregard errors. Only returned revStatus matters. */ | |
| 386 PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult, | |
| 387 plContext); | |
| 388 pkixErrorResult = NULL; | |
| 389 } | |
| 390 } | |
| 391 if ((!(revFlags & PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST) || | |
| 392 onlyUseRemoteMethods) && | |
| 393 chainVerificationState && | |
| 394 methodStatus[methodNum] == PKIX_RevStatus_NoInfo) { | |
| 395 if (!(methodFlags & PKIX_REV_M_FORBID_NETWORK_FETCHING)) { | |
| 396 PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; | |
| 397 PKIX_CHECK_NO_GOTO( | |
| 398 (*method->externalRevChecker)(cert, issuer, date, | |
| 399 method, | |
| 400 procParams, methodFlags, | |
| 401 &revStatus, | |
| 402 (CERTCRLEntryReasonCode *)
pReasonCode, | |
| 403 &nbioContext, plContext), | |
| 404 PKIX_REVCHECKERCHECKFAILED); | |
| 405 methodStatus[methodNum] = revStatus; | |
| 406 if (revStatus == PKIX_RevStatus_Revoked) { | |
| 407 /* if error was generated use it as final error. */ | |
| 408 overallStatus = PKIX_RevStatus_Revoked; | |
| 409 goto cleanup; | |
| 410 } | |
| 411 if (pkixErrorResult) { | |
| 412 /* Disregard errors. Only returned revStatus matters. */ | |
| 413 PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult, | |
| 414 plContext); | |
| 415 pkixErrorResult = NULL; | |
| 416 } | |
| 417 } else if (methodFlags & | |
| 418 PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) { | |
| 419 /* Info is not in the local cache. Network fetching is not | |
| 420 * allowed. If need to fail on missing fresh info for the | |
| 421 * the method, then we should fail right here.*/ | |
| 422 overallStatus = PKIX_RevStatus_Revoked; | |
| 423 goto cleanup; | |
| 424 } | |
| 425 } | |
| 426 /* If success and we should not check the next method, then | |
| 427 * return a success. */ | |
| 428 if (methodStatus[methodNum] == PKIX_RevStatus_Success && | |
| 429 !(methodFlags & PKIX_REV_M_CONTINUE_TESTING_ON_FRESH_INFO)) { | |
| 430 overallStatus = PKIX_RevStatus_Success; | |
| 431 goto cleanup; | |
| 432 } | |
| 433 } /* inner loop */ | |
| 434 if (!onlyUseRemoteMethods && | |
| 435 revFlags & PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST && | |
| 436 chainVerificationState) { | |
| 437 onlyUseRemoteMethods = PKIX_TRUE; | |
| 438 continue; | |
| 439 } | |
| 440 break; | |
| 441 } /* outer loop */ | |
| 442 | |
| 443 if (overallStatus == PKIX_RevStatus_NoInfo && | |
| 444 chainVerificationState) { | |
| 445 /* The following check makes sence only for chain | |
| 446 * validation step, sinse we do not fetch info while | |
| 447 * in the process of finding trusted anchor. | |
| 448 * For chain building step it is enough to know, that | |
| 449 * the cert was not directly revoked by any of the | |
| 450 * methods. */ | |
| 451 | |
| 452 /* Still have no info. But one of the method could | |
| 453 * have returned success status(possible if CONTINUE | |
| 454 * TESTING ON FRESH INFO flag was used). | |
| 455 * If any of the methods have returned Success status, | |
| 456 * the overallStatus should be success. */ | |
| 457 int methodNum = 0; | |
| 458 for (;methodNum < PKIX_RevocationMethod_MAX;methodNum++) { | |
| 459 if (methodStatus[methodNum] == PKIX_RevStatus_Success) { | |
| 460 overallStatus = PKIX_RevStatus_Success; | |
| 461 goto cleanup; | |
| 462 } | |
| 463 } | |
| 464 if (revFlags & PKIX_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE) { | |
| 465 overallStatus = PKIX_RevStatus_Revoked; | |
| 466 } | |
| 467 } | |
| 468 | |
| 469 cleanup: | |
| 470 *pRevStatus = overallStatus; | |
| 471 PKIX_DECREF(method); | |
| 472 | |
| 473 PKIX_RETURN(REVOCATIONCHECKER); | |
| 474 } | |
| 475 | |
| OLD | NEW |