| 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 theirs priorities */ | |
| 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 *pResult = (method1->priority > method2->priority); | |
| 156 | |
| 157 PKIX_RETURN(BUILD); | |
| 158 } | |
| 159 | |
| 160 | |
| 161 /* --Public-Functions--------------------------------------------- */ | |
| 162 | |
| 163 | |
| 164 /* | |
| 165 * FUNCTION: PKIX_RevocationChecker_Create (see comments in pkix_revchecker.h) | |
| 166 */ | |
| 167 PKIX_Error * | |
| 168 PKIX_RevocationChecker_Create( | |
| 169 PKIX_UInt32 leafMethodListFlags, | |
| 170 PKIX_UInt32 chainMethodListFlags, | |
| 171 PKIX_RevocationChecker **pChecker, | |
| 172 void *plContext) | |
| 173 { | |
| 174 PKIX_RevocationChecker *checker = NULL; | |
| 175 | |
| 176 PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_Create"); | |
| 177 PKIX_NULLCHECK_ONE(pChecker); | |
| 178 | |
| 179 PKIX_CHECK( | |
| 180 PKIX_PL_Object_Alloc(PKIX_REVOCATIONCHECKER_TYPE, | |
| 181 sizeof (PKIX_RevocationChecker), | |
| 182 (PKIX_PL_Object **)&checker, | |
| 183 plContext), | |
| 184 PKIX_COULDNOTCREATECERTCHAINCHECKEROBJECT); | |
| 185 | |
| 186 checker->leafMethodListFlags = leafMethodListFlags; | |
| 187 checker->chainMethodListFlags = chainMethodListFlags; | |
| 188 checker->leafMethodList = NULL; | |
| 189 checker->chainMethodList = NULL; | |
| 190 | |
| 191 *pChecker = checker; | |
| 192 checker = NULL; | |
| 193 | |
| 194 cleanup: | |
| 195 PKIX_DECREF(checker); | |
| 196 | |
| 197 PKIX_RETURN(REVOCATIONCHECKER); | |
| 198 } | |
| 199 | |
| 200 /* | |
| 201 * FUNCTION: PKIX_RevocationChecker_CreateAndAddMethod | |
| 202 */ | |
| 203 PKIX_Error * | |
| 204 PKIX_RevocationChecker_CreateAndAddMethod( | |
| 205 PKIX_RevocationChecker *revChecker, | |
| 206 PKIX_ProcessingParams *params, | |
| 207 PKIX_RevocationMethodType methodType, | |
| 208 PKIX_UInt32 flags, | |
| 209 PKIX_UInt32 priority, | |
| 210 PKIX_PL_VerifyCallback verificationFn, | |
| 211 PKIX_Boolean isLeafMethod, | |
| 212 void *plContext) | |
| 213 { | |
| 214 PKIX_List **methodList = NULL; | |
| 215 PKIX_List *unsortedList = NULL; | |
| 216 PKIX_List *certStores = NULL; | |
| 217 pkix_RevocationMethod *method = NULL; | |
| 218 pkix_LocalRevocationCheckFn *localRevChecker = NULL; | |
| 219 pkix_ExternalRevocationCheckFn *externRevChecker = NULL; | |
| 220 PKIX_UInt32 miFlags; | |
| 221 | |
| 222 PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_CreateAndAddMethod"); | |
| 223 PKIX_NULLCHECK_ONE(revChecker); | |
| 224 | |
| 225 /* If the caller has said "Either one is sufficient, then don't let the | |
| 226 * absence of any one method's info lead to an overall failure. | |
| 227 */ | |
| 228 miFlags = isLeafMethod ? revChecker->leafMethodListFlags | |
| 229 : revChecker->chainMethodListFlags; | |
| 230 if (miFlags & PKIX_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE) | |
| 231 flags &= ~PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO; | |
| 232 | |
| 233 switch (methodType) { | |
| 234 case PKIX_RevocationMethod_CRL: | |
| 235 localRevChecker = pkix_CrlChecker_CheckLocal; | |
| 236 externRevChecker = pkix_CrlChecker_CheckExternal; | |
| 237 PKIX_CHECK( | |
| 238 PKIX_ProcessingParams_GetCertStores(params, &certStores, | |
| 239 plContext), | |
| 240 PKIX_PROCESSINGPARAMSGETCERTSTORESFAILED); | |
| 241 PKIX_CHECK( | |
| 242 pkix_CrlChecker_Create(methodType, flags, priority, | |
| 243 localRevChecker, externRevChecker, | |
| 244 certStores, verificationFn, | |
| 245 &method, | |
| 246 plContext), | |
| 247 PKIX_COULDNOTCREATECRLCHECKEROBJECT); | |
| 248 break; | |
| 249 case PKIX_RevocationMethod_OCSP: | |
| 250 localRevChecker = pkix_OcspChecker_CheckLocal; | |
| 251 externRevChecker = pkix_OcspChecker_CheckExternal; | |
| 252 PKIX_CHECK( | |
| 253 pkix_OcspChecker_Create(methodType, flags, priority, | |
| 254 localRevChecker, externRevChecker, | |
| 255 verificationFn, | |
| 256 &method, | |
| 257 plContext), | |
| 258 PKIX_COULDNOTCREATEOCSPCHECKEROBJECT); | |
| 259 break; | |
| 260 default: | |
| 261 PKIX_ERROR(PKIX_INVALIDREVOCATIONMETHOD); | |
| 262 } | |
| 263 | |
| 264 if (isLeafMethod) { | |
| 265 methodList = &revChecker->leafMethodList; | |
| 266 } else { | |
| 267 methodList = &revChecker->chainMethodList; | |
| 268 } | |
| 269 | |
| 270 if (*methodList == NULL) { | |
| 271 PKIX_CHECK( | |
| 272 PKIX_List_Create(methodList, plContext), | |
| 273 PKIX_LISTCREATEFAILED); | |
| 274 } | |
| 275 unsortedList = *methodList; | |
| 276 PKIX_CHECK( | |
| 277 PKIX_List_AppendItem(unsortedList, (PKIX_PL_Object*)method, plContext), | |
| 278 PKIX_LISTAPPENDITEMFAILED); | |
| 279 PKIX_CHECK( | |
| 280 pkix_List_BubbleSort(unsortedList, | |
| 281 pkix_RevocationChecker_SortComparator, | |
| 282 methodList, plContext), | |
| 283 PKIX_LISTBUBBLESORTFAILED); | |
| 284 | |
| 285 cleanup: | |
| 286 PKIX_DECREF(method); | |
| 287 PKIX_DECREF(unsortedList); | |
| 288 PKIX_DECREF(certStores); | |
| 289 | |
| 290 PKIX_RETURN(REVOCATIONCHECKER); | |
| 291 } | |
| 292 | |
| 293 /* | |
| 294 * FUNCTION: PKIX_RevocationChecker_Check | |
| 295 */ | |
| 296 PKIX_Error * | |
| 297 PKIX_RevocationChecker_Check( | |
| 298 PKIX_PL_Cert *cert, | |
| 299 PKIX_PL_Cert *issuer, | |
| 300 PKIX_RevocationChecker *revChecker, | |
| 301 PKIX_ProcessingParams *procParams, | |
| 302 PKIX_Boolean chainVerificationState, | |
| 303 PKIX_Boolean testingLeafCert, | |
| 304 PKIX_RevocationStatus *pRevStatus, | |
| 305 PKIX_UInt32 *pReasonCode, | |
| 306 void **pNbioContext, | |
| 307 void *plContext) | |
| 308 { | |
| 309 PKIX_RevocationStatus overallStatus = PKIX_RevStatus_NoInfo; | |
| 310 PKIX_RevocationStatus methodStatus[PKIX_RevocationMethod_MAX]; | |
| 311 PKIX_Boolean onlyUseRemoteMethods = PKIX_FALSE; | |
| 312 PKIX_UInt32 revFlags = 0; | |
| 313 PKIX_List *revList = NULL; | |
| 314 PKIX_PL_Date *date = NULL; | |
| 315 pkix_RevocationMethod *method = NULL; | |
| 316 void *nbioContext; | |
| 317 int tries; | |
| 318 | |
| 319 PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_Check"); | |
| 320 PKIX_NULLCHECK_TWO(revChecker, procParams); | |
| 321 | |
| 322 nbioContext = *pNbioContext; | |
| 323 *pNbioContext = NULL; | |
| 324 | |
| 325 if (testingLeafCert) { | |
| 326 revList = revChecker->leafMethodList; | |
| 327 revFlags = revChecker->leafMethodListFlags; | |
| 328 } else { | |
| 329 revList = revChecker->chainMethodList; | |
| 330 revFlags = revChecker->chainMethodListFlags; | |
| 331 } | |
| 332 if (!revList) { | |
| 333 /* Return NoInfo status */ | |
| 334 goto cleanup; | |
| 335 } | |
| 336 | |
| 337 PORT_Memset(methodStatus, PKIX_RevStatus_NoInfo, | |
| 338 sizeof(PKIX_RevocationStatus) * PKIX_RevocationMethod_MAX); | |
| 339 | |
| 340 date = procParams->date; | |
| 341 | |
| 342 /* Need to have two loops if we testing all local info first: | |
| 343 * first we are going to test all local(cached) info | |
| 344 * second, all remote info(fetching) */ | |
| 345 for (tries = 0;tries < 2;tries++) { | |
| 346 int methodNum = 0; | |
| 347 for (;methodNum < revList->length;methodNum++) { | |
| 348 PKIX_UInt32 methodFlags = 0; | |
| 349 | |
| 350 PKIX_DECREF(method); | |
| 351 PKIX_CHECK( | |
| 352 PKIX_List_GetItem(revList, methodNum, | |
| 353 (PKIX_PL_Object**)&method, plContext), | |
| 354 PKIX_LISTGETITEMFAILED); | |
| 355 methodFlags = method->flags; | |
| 356 if (!(methodFlags & PKIX_REV_M_TEST_USING_THIS_METHOD)) { | |
| 357 /* Will not check with this method. Skipping... */ | |
| 358 continue; | |
| 359 } | |
| 360 if (!onlyUseRemoteMethods && | |
| 361 methodStatus[methodNum] == PKIX_RevStatus_NoInfo) { | |
| 362 PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; | |
| 363 PKIX_CHECK_NO_GOTO( | |
| 364 (*method->localRevChecker)(cert, issuer, date, | |
| 365 method, procParams, | |
| 366 methodFlags, | |
| 367 chainVerificationState, | |
| 368 &revStatus, | |
| 369 pReasonCode, plContext), | |
| 370 PKIX_REVCHECKERCHECKFAILED); | |
| 371 methodStatus[methodNum] = revStatus; | |
| 372 if (revStatus == PKIX_RevStatus_Revoked) { | |
| 373 /* if error was generated use it as final error. */ | |
| 374 overallStatus = PKIX_RevStatus_Revoked; | |
| 375 goto cleanup; | |
| 376 } | |
| 377 if (pkixErrorResult) { | |
| 378 /* Disregard errors. Only returned revStatus matters. */ | |
| 379 PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult, | |
| 380 plContext); | |
| 381 pkixErrorResult = NULL; | |
| 382 } | |
| 383 } | |
| 384 if ((!(revFlags & PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST) || | |
| 385 onlyUseRemoteMethods) && | |
| 386 chainVerificationState && | |
| 387 methodStatus[methodNum] == PKIX_RevStatus_NoInfo) { | |
| 388 if (!(methodFlags & PKIX_REV_M_FORBID_NETWORK_FETCHING)) { | |
| 389 PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; | |
| 390 PKIX_CHECK_NO_GOTO( | |
| 391 (*method->externalRevChecker)(cert, issuer, date, | |
| 392 method, | |
| 393 procParams, methodFlags, | |
| 394 &revStatus, pReasonCode, | |
| 395 &nbioContext, plContext), | |
| 396 PKIX_REVCHECKERCHECKFAILED); | |
| 397 methodStatus[methodNum] = revStatus; | |
| 398 if (revStatus == PKIX_RevStatus_Revoked) { | |
| 399 /* if error was generated use it as final error. */ | |
| 400 overallStatus = PKIX_RevStatus_Revoked; | |
| 401 goto cleanup; | |
| 402 } | |
| 403 if (pkixErrorResult) { | |
| 404 /* Disregard errors. Only returned revStatus matters. */ | |
| 405 PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult, | |
| 406 plContext); | |
| 407 pkixErrorResult = NULL; | |
| 408 } | |
| 409 } else if (methodFlags & | |
| 410 PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) { | |
| 411 /* Info is not in the local cache. Network fetching is not | |
| 412 * allowed. If need to fail on missing fresh info for the | |
| 413 * the method, then we should fail right here.*/ | |
| 414 overallStatus = PKIX_RevStatus_Revoked; | |
| 415 goto cleanup; | |
| 416 } | |
| 417 } | |
| 418 /* If success and we should not check the next method, then | |
| 419 * return a success. */ | |
| 420 if (methodStatus[methodNum] == PKIX_RevStatus_Success && | |
| 421 !(methodFlags & PKIX_REV_M_CONTINUE_TESTING_ON_FRESH_INFO)) { | |
| 422 overallStatus = PKIX_RevStatus_Success; | |
| 423 goto cleanup; | |
| 424 } | |
| 425 } /* inner loop */ | |
| 426 if (!onlyUseRemoteMethods && | |
| 427 revFlags & PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST && | |
| 428 chainVerificationState) { | |
| 429 onlyUseRemoteMethods = PKIX_TRUE; | |
| 430 continue; | |
| 431 } | |
| 432 break; | |
| 433 } /* outer loop */ | |
| 434 | |
| 435 if (overallStatus == PKIX_RevStatus_NoInfo && | |
| 436 chainVerificationState) { | |
| 437 /* The following check makes sence only for chain | |
| 438 * validation step, sinse we do not fetch info while | |
| 439 * in the process of finding trusted anchor. | |
| 440 * For chain building step it is enough to know, that | |
| 441 * the cert was not directly revoked by any of the | |
| 442 * methods. */ | |
| 443 | |
| 444 /* Still have no info. But one of the method could | |
| 445 * have returned success status(possible if CONTINUE | |
| 446 * TESTING ON FRESH INFO flag was used). | |
| 447 * If any of the methods have returned Success status, | |
| 448 * the overallStatus should be success. */ | |
| 449 int methodNum = 0; | |
| 450 for (;methodNum < PKIX_RevocationMethod_MAX;methodNum++) { | |
| 451 if (methodStatus[methodNum] == PKIX_RevStatus_Success) { | |
| 452 overallStatus = PKIX_RevStatus_Success; | |
| 453 goto cleanup; | |
| 454 } | |
| 455 } | |
| 456 if (revFlags & PKIX_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE) { | |
| 457 overallStatus = PKIX_RevStatus_Revoked; | |
| 458 } | |
| 459 } | |
| 460 | |
| 461 cleanup: | |
| 462 *pRevStatus = overallStatus; | |
| 463 PKIX_DECREF(method); | |
| 464 | |
| 465 PKIX_RETURN(REVOCATIONCHECKER); | |
| 466 } | |
| 467 | |
| OLD | NEW |