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 |