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

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rwxr-xr-x

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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  */
    11 #include "pkix_revocationchecker.h"
    12 #include "pkix_tools.h"
    14 /* --Private-Functions-------------------------------------------- */
    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;
    27         PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_Destroy");
    28         PKIX_NULLCHECK_ONE(object);
    30         /* Check that this object is a revocation checker */
    31         PKIX_CHECK(pkix_CheckType
    32                     (object, PKIX_REVOCATIONCHECKER_TYPE, plContext),
    33                     PKIX_OBJECTNOTREVOCATIONCHECKER);
    35         checker = (PKIX_RevocationChecker *)object;
    37         PKIX_DECREF(checker->leafMethodList);
    38         PKIX_DECREF(checker->chainMethodList);
    40 cleanup:
    42         PKIX_RETURN(REVOCATIONCHECKER);
    43 }
    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;
    60         PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_Duplicate");
    61         PKIX_NULLCHECK_TWO(object, pNewObject);
    63         PKIX_CHECK(pkix_CheckType
    64                     (object, PKIX_REVOCATIONCHECKER_TYPE, plContext),
    65                     PKIX_OBJECTNOTCERTCHAINCHECKER);
    67         checker = (PKIX_RevocationChecker *)object;
    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         }
    84         PKIX_CHECK(
    85             PKIX_RevocationChecker_Create(checker->leafMethodListFlags,
    86                                           checker->chainMethodListFlags,
    87                                           &checkerDuplicate,
    88                                           plContext),
    89             PKIX_REVOCATIONCHECKERCREATEFAILED);
    91         checkerDuplicate->leafMethodList = dupLeafList;
    92         checkerDuplicate->chainMethodList = dupChainList;
    93         dupLeafList = NULL;
    94         dupChainList = NULL;
    96         *pNewObject = (PKIX_PL_Object *)checkerDuplicate;
    98 cleanup:
    99         PKIX_DECREF(dupLeafList);
   100         PKIX_DECREF(dupChainList);
   102         PKIX_RETURN(REVOCATIONCHECKER);
   103 }
   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;
   123         PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_RegisterSelf");
   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;
   135         systemClasses[PKIX_REVOCATIONCHECKER_TYPE] = entry;
   137         PKIX_RETURN(REVOCATIONCHECKER);
   138 }
   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;
   150     PKIX_ENTER(BUILD, "pkix_RevocationChecker_SortComparator");
   152     method1 = (pkix_RevocationMethod *)obj1;
   153     method2 = (pkix_RevocationMethod *)obj2;
   155     *pResult = (method1->priority > method2->priority);
   157     PKIX_RETURN(BUILD);
   158 }
   161 /* --Public-Functions--------------------------------------------- */
   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;
   176     PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_Create");
   177     PKIX_NULLCHECK_ONE(pChecker);
   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);
   186     checker->leafMethodListFlags = leafMethodListFlags;
   187     checker->chainMethodListFlags = chainMethodListFlags;
   188     checker->leafMethodList = NULL;
   189     checker->chainMethodList = NULL;
   191     *pChecker = checker;
   192     checker = NULL;
   194 cleanup:
   195     PKIX_DECREF(checker);
   197     PKIX_RETURN(REVOCATIONCHECKER);
   198 }
   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;
   222     PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_CreateAndAddMethod");
   223     PKIX_NULLCHECK_ONE(revChecker);
   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;
   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     }
   264     if (isLeafMethod) {
   265         methodList = &revChecker->leafMethodList;
   266     } else {
   267         methodList = &revChecker->chainMethodList;
   268     }
   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);
   285 cleanup:
   286     PKIX_DECREF(method);
   287     PKIX_DECREF(unsortedList);
   288     PKIX_DECREF(certStores);
   290     PKIX_RETURN(REVOCATIONCHECKER);
   291 }
   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;
   319     PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_Check");
   320     PKIX_NULLCHECK_TWO(revChecker, procParams);
   322     nbioContext = *pNbioContext;
   323     *pNbioContext = NULL;
   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     }
   337     PORT_Memset(methodStatus, PKIX_RevStatus_NoInfo,
   338                 sizeof(PKIX_RevocationStatus) * PKIX_RevocationMethod_MAX);
   340     date = procParams->date;
   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;
   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 */
   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. */
   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     }
   461 cleanup:
   462     *pRevStatus = overallStatus;
   463     PKIX_DECREF(method);
   465     PKIX_RETURN(REVOCATIONCHECKER);
   466 }

mercurial