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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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_ocspchecker.c
     6  *
     7  * OcspChecker Object Functions
     8  *
     9  */
    11 #include "pkix_ocspchecker.h"
    12 #include "pkix_pl_ocspcertid.h"
    13 #include "pkix_error.h"
    16 /* --Private-Data-and-Types--------------------------------------- */
    18 typedef struct pkix_OcspCheckerStruct {
    19     /* RevocationMethod is the super class of OcspChecker. */
    20     pkix_RevocationMethod method;
    21     PKIX_PL_VerifyCallback certVerifyFcn;
    22 } pkix_OcspChecker;
    24 /* --Private-Functions-------------------------------------------- */
    26 /*
    27  * FUNCTION: pkix_OcspChecker_Destroy
    28  *      (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
    29  */
    30 static PKIX_Error *
    31 pkix_OcspChecker_Destroy(
    32         PKIX_PL_Object *object,
    33         void *plContext)
    34 {
    35     return NULL;
    36 }
    38 /*
    39  * FUNCTION: pkix_OcspChecker_RegisterSelf
    40  * DESCRIPTION:
    41  *  Registers PKIX_OCSPCHECKER_TYPE and its related functions with
    42  *  systemClasses[]
    43  * THREAD SAFETY:
    44  *  Not Thread Safe - for performance and complexity reasons
    45  *
    46  *  Since this function is only called by PKIX_PL_Initialize, which should
    47  *  only be called once, it is acceptable that this function is not
    48  *  thread-safe.
    49  */
    50 PKIX_Error *
    51 pkix_OcspChecker_RegisterSelf(void *plContext)
    52 {
    53         extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
    54         pkix_ClassTable_Entry* entry = &systemClasses[PKIX_OCSPCHECKER_TYPE];
    56         PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_RegisterSelf");
    58         entry->description = "OcspChecker";
    59         entry->typeObjectSize = sizeof(pkix_OcspChecker);
    60         entry->destructor = pkix_OcspChecker_Destroy;
    62         PKIX_RETURN(OCSPCHECKER);
    63 }
    66 /*
    67  * FUNCTION: pkix_OcspChecker_Create
    68  */
    69 PKIX_Error *
    70 pkix_OcspChecker_Create(PKIX_RevocationMethodType methodType,
    71                         PKIX_UInt32 flags,
    72                         PKIX_UInt32 priority,
    73                         pkix_LocalRevocationCheckFn localRevChecker,
    74                         pkix_ExternalRevocationCheckFn externalRevChecker,
    75                         PKIX_PL_VerifyCallback verifyFn,
    76                         pkix_RevocationMethod **pChecker,
    77                         void *plContext)
    78 {
    79         pkix_OcspChecker *method = NULL;
    81         PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_Create");
    82         PKIX_NULLCHECK_ONE(pChecker);
    84         PKIX_CHECK(PKIX_PL_Object_Alloc
    85                     (PKIX_OCSPCHECKER_TYPE,
    86                     sizeof (pkix_OcspChecker),
    87                     (PKIX_PL_Object **)&method,
    88                     plContext),
    89                     PKIX_COULDNOTCREATECERTCHAINCHECKEROBJECT);
    91         pkixErrorResult = pkix_RevocationMethod_Init(
    92             (pkix_RevocationMethod*)method, methodType, flags,  priority,
    93             localRevChecker, externalRevChecker, plContext);
    94         if (pkixErrorResult) {
    95             goto cleanup;
    96         }
    97         method->certVerifyFcn = (PKIX_PL_VerifyCallback)verifyFn;
    99         *pChecker = (pkix_RevocationMethod*)method;
   100         method = NULL;
   102 cleanup:
   103         PKIX_DECREF(method);
   105         PKIX_RETURN(OCSPCHECKER);
   106 }
   108 /*
   109  * FUNCTION: pkix_OcspChecker_MapResultCodeToRevStatus
   110  */
   111 PKIX_RevocationStatus
   112 pkix_OcspChecker_MapResultCodeToRevStatus(SECErrorCodes resultCode)
   113 {
   114         switch (resultCode) {
   115             case SEC_ERROR_REVOKED_CERTIFICATE:
   116                 return PKIX_RevStatus_Revoked;
   117             default:
   118                 return PKIX_RevStatus_NoInfo;
   119         }
   120 }
   122 /* --Public-Functions--------------------------------------------- */
   124 /*
   125  * FUNCTION: pkix_OcspChecker_Check (see comments in pkix_checker.h)
   126  */
   128 /*
   129  * The OCSPChecker is created in an idle state, and remains in this state until
   130  * either (a) the default Responder has been set and enabled, and a Check
   131  * request is received with no responder specified, or (b) a Check request is
   132  * received with a specified responder. A request message is constructed and
   133  * given to the HttpClient. If non-blocking I/O is used the client may return
   134  * with WOULDBLOCK, in which case the OCSPChecker returns the WOULDBLOCK
   135  * condition to its caller in turn. On a subsequent call the I/O is resumed.
   136  * When a response is received it is decoded and the results provided to the
   137  * caller.
   138  *
   139  */
   140 PKIX_Error *
   141 pkix_OcspChecker_CheckLocal(
   142         PKIX_PL_Cert *cert,
   143         PKIX_PL_Cert *issuer,
   144         PKIX_PL_Date *date,
   145         pkix_RevocationMethod *checkerObject,
   146         PKIX_ProcessingParams *procParams,
   147         PKIX_UInt32 methodFlags,
   148         PKIX_Boolean chainVerificationState,
   149         PKIX_RevocationStatus *pRevStatus,
   150         PKIX_UInt32 *pReasonCode,
   151         void *plContext)
   152 {
   153         PKIX_PL_OcspCertID    *cid = NULL;
   154         PKIX_Boolean           hasFreshStatus = PKIX_FALSE;
   155         PKIX_Boolean           statusIsGood = PKIX_FALSE;
   156         SECErrorCodes          resultCode = SEC_ERROR_REVOKED_CERTIFICATE_OCSP;
   157         PKIX_RevocationStatus  revStatus = PKIX_RevStatus_NoInfo;
   159         PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_CheckLocal");
   161         PKIX_CHECK(
   162             PKIX_PL_OcspCertID_Create(cert, NULL, &cid,
   163                                       plContext),
   164             PKIX_OCSPCERTIDCREATEFAILED);
   165         if (!cid) {
   166             goto cleanup;
   167         }
   169         PKIX_CHECK(
   170             PKIX_PL_OcspCertID_GetFreshCacheStatus(cid, date,
   171                                                    &hasFreshStatus,
   172                                                    &statusIsGood,
   173                                                    &resultCode,
   174                                                    plContext),
   175             PKIX_OCSPCERTIDGETFRESHCACHESTATUSFAILED);
   176         if (hasFreshStatus) {
   177             if (statusIsGood) {
   178                 revStatus = PKIX_RevStatus_Success;
   179                 resultCode = 0;
   180             } else {
   181                 revStatus = pkix_OcspChecker_MapResultCodeToRevStatus(resultCode);
   182             }
   183         }
   185 cleanup:
   186         *pRevStatus = revStatus;
   188         /* ocsp carries only tree statuses: good, bad, and unknown.
   189          * revStatus is used to pass them. reasonCode is always set
   190          * to be unknown. */
   191         *pReasonCode = crlEntryReasonUnspecified;
   192         PKIX_DECREF(cid);
   194         PKIX_RETURN(OCSPCHECKER);
   195 }
   198 /*
   199  * The OCSPChecker is created in an idle state, and remains in this state until
   200  * either (a) the default Responder has been set and enabled, and a Check
   201  * request is received with no responder specified, or (b) a Check request is
   202  * received with a specified responder. A request message is constructed and
   203  * given to the HttpClient. When a response is received it is decoded and the
   204  * results provided to the caller.
   205  *
   206  * During the most recent enhancement of this function, it has been found that
   207  * it doesn't correctly implement non-blocking I/O.
   208  * 
   209  * The nbioContext is used in two places, for "response-obtaining" and
   210  * for "response-verification".
   211  * 
   212  * However, if this function gets called to resume, it always
   213  * repeats the "request creation" and "response fetching" steps!
   214  * As a result, the earlier operation is never resumed.
   215  */
   216 PKIX_Error *
   217 pkix_OcspChecker_CheckExternal(
   218         PKIX_PL_Cert *cert,
   219         PKIX_PL_Cert *issuer,
   220         PKIX_PL_Date *date,
   221         pkix_RevocationMethod *checkerObject,
   222         PKIX_ProcessingParams *procParams,
   223         PKIX_UInt32 methodFlags,
   224         PKIX_RevocationStatus *pRevStatus,
   225         PKIX_UInt32 *pReasonCode,
   226         void **pNBIOContext,
   227         void *plContext)
   228 {
   229         SECErrorCodes resultCode = SEC_ERROR_REVOKED_CERTIFICATE_OCSP;
   230         PKIX_Boolean uriFound = PKIX_FALSE;
   231         PKIX_Boolean passed = PKIX_TRUE;
   232         pkix_OcspChecker *checker = NULL;
   233         PKIX_PL_OcspCertID *cid = NULL;
   234         PKIX_PL_OcspRequest *request = NULL;
   235         PKIX_PL_OcspResponse *response = NULL;
   236         PKIX_PL_Date *validity = NULL;
   237         PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo;
   238         void *nbioContext = NULL;
   239         enum { stageGET, stagePOST } currentStage;
   240         PRBool retry = PR_FALSE;
   242         PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_CheckExternal");
   244         PKIX_CHECK(
   245             pkix_CheckType((PKIX_PL_Object*)checkerObject,
   246                            PKIX_OCSPCHECKER_TYPE, plContext),
   247                 PKIX_OBJECTNOTOCSPCHECKER);
   249         checker = (pkix_OcspChecker *)checkerObject;
   251         PKIX_CHECK(
   252             PKIX_PL_OcspCertID_Create(cert, NULL, &cid,
   253                                       plContext),
   254             PKIX_OCSPCERTIDCREATEFAILED);
   256         /* create request */
   257         PKIX_CHECK(
   258             pkix_pl_OcspRequest_Create(cert, cid, validity, NULL, 
   259                                        methodFlags, &uriFound, &request,
   260                                        plContext),
   261             PKIX_OCSPREQUESTCREATEFAILED);
   263         if (uriFound == PKIX_FALSE) {
   264             /* no caching for certs lacking URI */
   265             resultCode = 0;
   266             goto cleanup;
   267         }
   269         if (methodFlags & CERT_REV_M_FORCE_POST_METHOD_FOR_OCSP) {
   270             /* Do not try HTTP GET, only HTTP POST */
   271             currentStage = stagePOST;
   272         } else {
   273             /* Try HTTP GET first, falling back to POST */
   274             currentStage = stageGET;
   275         }
   277         do {
   278                 const char *method;
   279                 passed = PKIX_TRUE;
   281                 retry = PR_FALSE;
   282                 if (currentStage == stageGET) {
   283                         method = "GET";
   284                 } else {
   285                         PORT_Assert(currentStage == stagePOST);
   286                         method = "POST";
   287                 }
   289                 /* send request and create a response object */
   290                 PKIX_CHECK_NO_GOTO(
   291                     pkix_pl_OcspResponse_Create(request, method, NULL,
   292                                                 checker->certVerifyFcn,
   293                                                 &nbioContext,
   294                                                 &response,
   295                                                 plContext),
   296                     PKIX_OCSPRESPONSECREATEFAILED);
   298                 if (pkixErrorResult) {
   299                     passed = PKIX_FALSE;
   300                 }
   302                 if (passed && nbioContext != 0) {
   303                         *pNBIOContext = nbioContext;
   304                         goto cleanup;
   305                 }
   307                 if (passed){
   308                         PKIX_CHECK_NO_GOTO(
   309                             pkix_pl_OcspResponse_Decode(response, &passed,
   310                                                         &resultCode, plContext),
   311                             PKIX_OCSPRESPONSEDECODEFAILED);
   312                         if (pkixErrorResult) {
   313                             passed = PKIX_FALSE;
   314                         }
   315                 }
   317                 if (passed){
   318                         PKIX_CHECK_NO_GOTO(
   319                             pkix_pl_OcspResponse_GetStatus(response, &passed,
   320                                                            &resultCode, plContext),
   321                             PKIX_OCSPRESPONSEGETSTATUSRETURNEDANERROR);
   322                         if (pkixErrorResult) {
   323                             passed = PKIX_FALSE;
   324                         }
   325                 }
   327                 if (passed){
   328                         PKIX_CHECK_NO_GOTO(
   329                             pkix_pl_OcspResponse_VerifySignature(response, cert,
   330                                                                  procParams, &passed, 
   331                                                                  &nbioContext, plContext),
   332                             PKIX_OCSPRESPONSEVERIFYSIGNATUREFAILED);
   333                         if (pkixErrorResult) {
   334                             passed = PKIX_FALSE;
   335                         } else {
   336                                 if (nbioContext != 0) {
   337                                         *pNBIOContext = nbioContext;
   338                                         goto cleanup;
   339                                 }
   340                         }
   341                 }
   343                 if (!passed && currentStage == stagePOST) {
   344                         /* We won't retry a POST failure, so it's final.
   345                          * Because the following block with its call to
   346                          *   pkix_pl_OcspResponse_GetStatusForCert
   347                          * will take care of caching good or bad state,
   348                          * but we only execute that next block if there hasn't
   349                          * been a failure yet, we must cache the POST
   350                          * failure now.
   351                          */
   353                         if (cid && cid->certID) {
   354                                 /* Caching MIGHT consume the cid. */
   355                                 PKIX_Error *err;
   356                                 err = PKIX_PL_OcspCertID_RememberOCSPProcessingFailure(
   357                                         cid, plContext);
   358                                 if (err) {
   359                                         PKIX_PL_Object_DecRef((PKIX_PL_Object*)err, plContext);
   360                                 }
   361                         }
   362                 }
   364                 if (passed){
   365                         PKIX_Boolean allowCachingOfFailures =
   366                                 (currentStage == stagePOST) ? PKIX_TRUE : PKIX_FALSE;
   368                         PKIX_CHECK_NO_GOTO(
   369                             pkix_pl_OcspResponse_GetStatusForCert(cid, response,
   370                                                                   allowCachingOfFailures,
   371                                                                   date,
   372                                                                   &passed, &resultCode,
   373                                                                   plContext),
   374                             PKIX_OCSPRESPONSEGETSTATUSFORCERTFAILED);
   375                         if (pkixErrorResult) {
   376                             passed = PKIX_FALSE;
   377                         } else if (passed == PKIX_FALSE) {
   378                                 revStatus = pkix_OcspChecker_MapResultCodeToRevStatus(resultCode);
   379                         } else {
   380                                 revStatus = PKIX_RevStatus_Success;
   381                         }
   382                 }
   384                 if (currentStage == stageGET && revStatus != PKIX_RevStatus_Success &&
   385                                                 revStatus != PKIX_RevStatus_Revoked) {
   386                         /* we'll retry */
   387                         PKIX_DECREF(response);
   388                         retry = PR_TRUE;
   389                         currentStage = stagePOST;
   390                         revStatus = PKIX_RevStatus_NoInfo;
   391                         if (pkixErrorResult) {
   392                                 PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult,
   393                                                       plContext);
   394                                 pkixErrorResult = NULL;
   395                         }
   396                 }
   397         } while (retry);
   399 cleanup:
   400         if (revStatus == PKIX_RevStatus_NoInfo && (uriFound || 
   401 	    methodFlags & PKIX_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE) &&
   402             methodFlags & PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) {
   403             revStatus = PKIX_RevStatus_Revoked;
   404         }
   405         *pRevStatus = revStatus;
   407         /* ocsp carries only three statuses: good, bad, and unknown.
   408          * revStatus is used to pass them. reasonCode is always set
   409          * to be unknown. */
   410         *pReasonCode = crlEntryReasonUnspecified;
   412         PKIX_DECREF(cid);
   413         PKIX_DECREF(request);
   414         PKIX_DECREF(response);
   416         PKIX_RETURN(OCSPCHECKER);
   417 }

mercurial