PageRenderTime 46ms CodeModel.GetById 1ms app.highlight 36ms RepoModel.GetById 1ms app.codeStats 1ms

/security/nss/lib/libpkix/pkix/checker/pkix_revocationchecker.c

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