tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pkix_pl_ocspresponse.c (38019B)


      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_pl_ocspresponse.c
      6 *
      7 */
      8 
      9 #include "pkix_pl_ocspresponse.h"
     10 
     11 /* ----Public functions------------------------------------- */
     12 /*
     13 * This is the libpkix replacement for CERT_VerifyOCSPResponseSignature.
     14 * It is used if it has been set as the verifyFcn member of ocspChecker.
     15 */
     16 PKIX_Error *
     17 PKIX_PL_OcspResponse_UseBuildChain(
     18        PKIX_PL_Cert *signerCert,
     19 PKIX_PL_Date *producedAt,
     20        PKIX_ProcessingParams *procParams,
     21        void **pNBIOContext,
     22        void **pState,
     23        PKIX_BuildResult **pBuildResult,
     24        PKIX_VerifyNode **pVerifyTree,
     25 void *plContext)
     26 {
     27        PKIX_ProcessingParams *caProcParams = NULL;
     28        PKIX_PL_Date *date = NULL;
     29        PKIX_ComCertSelParams *certSelParams = NULL;
     30        PKIX_CertSelector *certSelector = NULL;
     31        void *nbioContext = NULL;
     32        PKIX_Error *buildError = NULL;
     33 
     34        PKIX_ENTER(OCSPRESPONSE, "pkix_OcspResponse_UseBuildChain");
     35        PKIX_NULLCHECK_THREE(signerCert, producedAt, procParams);
     36        PKIX_NULLCHECK_THREE(pNBIOContext, pState, pBuildResult);
     37 
     38        nbioContext = *pNBIOContext;
     39        *pNBIOContext = NULL;
     40 
     41        /* Are we resuming after a WOULDBLOCK return, or starting anew ? */
     42        if (nbioContext == NULL) {
     43                /* Starting anew */
     44 	PKIX_CHECK(PKIX_PL_Object_Duplicate
     45                        ((PKIX_PL_Object *)procParams,
     46                        (PKIX_PL_Object **)&caProcParams,
     47                        plContext),
     48        	        PKIX_OBJECTDUPLICATEFAILED);
     49 
     50 	PKIX_CHECK(PKIX_ProcessingParams_SetDate(procParams, date, plContext),
     51                 PKIX_PROCESSINGPARAMSSETDATEFAILED);
     52 
     53         /* create CertSelector with target certificate in params */
     54 
     55 	PKIX_CHECK(PKIX_CertSelector_Create
     56                 (NULL, NULL, &certSelector, plContext),
     57                 PKIX_CERTSELECTORCREATEFAILED);
     58 
     59 	PKIX_CHECK(PKIX_ComCertSelParams_Create
     60                 (&certSelParams, plContext),
     61                 PKIX_COMCERTSELPARAMSCREATEFAILED);
     62 
     63         PKIX_CHECK(PKIX_ComCertSelParams_SetCertificate
     64        	        (certSelParams, signerCert, plContext),
     65                	PKIX_COMCERTSELPARAMSSETCERTIFICATEFAILED);
     66 
     67         PKIX_CHECK(PKIX_CertSelector_SetCommonCertSelectorParams
     68                 (certSelector, certSelParams, plContext),
     69                 PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED);
     70 
     71         PKIX_CHECK(PKIX_ProcessingParams_SetTargetCertConstraints
     72        	        (caProcParams, certSelector, plContext),
     73                	PKIX_PROCESSINGPARAMSSETTARGETCERTCONSTRAINTSFAILED);
     74 }
     75 
     76        buildError = PKIX_BuildChain
     77                (caProcParams,
     78                &nbioContext,
     79                pState,
     80                pBuildResult,
     81 	pVerifyTree,
     82                plContext);
     83 
     84        /* non-null nbioContext means the build would block */
     85        if (nbioContext != NULL) {
     86 
     87                *pNBIOContext = nbioContext;
     88 
     89        /* no buildResult means the build has failed */
     90        } else if (buildError) {
     91                pkixErrorResult = buildError;
     92                buildError = NULL;
     93        } else {
     94                PKIX_DECREF(*pState);
     95        }
     96 
     97 cleanup:
     98 
     99        PKIX_DECREF(caProcParams);
    100        PKIX_DECREF(date);
    101        PKIX_DECREF(certSelParams);
    102        PKIX_DECREF(certSelector);
    103 
    104        PKIX_RETURN(OCSPRESPONSE);
    105 }
    106 
    107 /* --Private-OcspResponse-Functions------------------------------------- */
    108 
    109 /*
    110 * FUNCTION: pkix_pl_OcspResponse_Destroy
    111 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
    112 */
    113 static PKIX_Error *
    114 pkix_pl_OcspResponse_Destroy(
    115        PKIX_PL_Object *object,
    116        void *plContext)
    117 {
    118        PKIX_PL_OcspResponse *ocspRsp = NULL;
    119        const SEC_HttpClientFcn *httpClient = NULL;
    120        const SEC_HttpClientFcnV1 *hcv1 = NULL;
    121 
    122        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Destroy");
    123        PKIX_NULLCHECK_ONE(object);
    124 
    125        PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPRESPONSE_TYPE, plContext),
    126                    PKIX_OBJECTNOTANOCSPRESPONSE);
    127 
    128        ocspRsp = (PKIX_PL_OcspResponse *)object;
    129 
    130        if (ocspRsp->nssOCSPResponse != NULL) {
    131                CERT_DestroyOCSPResponse(ocspRsp->nssOCSPResponse);
    132                ocspRsp->nssOCSPResponse = NULL;
    133        }
    134 
    135        if (ocspRsp->signerCert != NULL) {
    136                CERT_DestroyCertificate(ocspRsp->signerCert);
    137                ocspRsp->signerCert = NULL;
    138        }
    139 
    140        httpClient = (const SEC_HttpClientFcn *)(ocspRsp->httpClient);
    141 
    142        if (httpClient && (httpClient->version == 1)) {
    143 
    144                hcv1 = &(httpClient->fcnTable.ftable1);
    145 
    146                if (ocspRsp->sessionRequest != NULL) {
    147                    (*hcv1->freeFcn)(ocspRsp->sessionRequest);
    148                    ocspRsp->sessionRequest = NULL;
    149                }
    150 
    151                if (ocspRsp->serverSession != NULL) {
    152                    (*hcv1->freeSessionFcn)(ocspRsp->serverSession);
    153                    ocspRsp->serverSession = NULL;
    154                }
    155        }
    156 
    157        if (ocspRsp->arena != NULL) {
    158                PORT_FreeArena(ocspRsp->arena, PR_FALSE);
    159                ocspRsp->arena = NULL;
    160        }
    161 
    162 PKIX_DECREF(ocspRsp->producedAtDate);
    163 PKIX_DECREF(ocspRsp->pkixSignerCert);
    164 PKIX_DECREF(ocspRsp->request);
    165 
    166 cleanup:
    167 
    168        PKIX_RETURN(OCSPRESPONSE);
    169 }
    170 
    171 /*
    172 * FUNCTION: pkix_pl_OcspResponse_Hashcode
    173 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
    174 */
    175 static PKIX_Error *
    176 pkix_pl_OcspResponse_Hashcode(
    177        PKIX_PL_Object *object,
    178        PKIX_UInt32 *pHashcode,
    179        void *plContext)
    180 {
    181        PKIX_PL_OcspResponse *ocspRsp = NULL;
    182 
    183        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Hashcode");
    184        PKIX_NULLCHECK_TWO(object, pHashcode);
    185 
    186        PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPRESPONSE_TYPE, plContext),
    187                    PKIX_OBJECTNOTANOCSPRESPONSE);
    188 
    189        ocspRsp = (PKIX_PL_OcspResponse *)object;
    190 
    191        if (ocspRsp->encodedResponse->data == NULL) {
    192                *pHashcode = 0;
    193        } else {
    194                PKIX_CHECK(pkix_hash
    195                        (ocspRsp->encodedResponse->data,
    196                        ocspRsp->encodedResponse->len,
    197                        pHashcode,
    198                        plContext),
    199                        PKIX_HASHFAILED);
    200        }
    201 
    202 cleanup:
    203 
    204        PKIX_RETURN(OCSPRESPONSE);
    205 }
    206 
    207 /*
    208 * FUNCTION: pkix_pl_OcspResponse_Equals
    209 * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
    210 */
    211 static PKIX_Error *
    212 pkix_pl_OcspResponse_Equals(
    213        PKIX_PL_Object *firstObj,
    214        PKIX_PL_Object *secondObj,
    215        PKIX_Boolean *pResult,
    216        void *plContext)
    217 {
    218        PKIX_UInt32 secondType = 0;
    219        PKIX_UInt32 firstLen = 0;
    220        PKIX_UInt32 i = 0;
    221        PKIX_PL_OcspResponse *rsp1 = NULL;
    222        PKIX_PL_OcspResponse *rsp2 = NULL;
    223        const unsigned char *firstData = NULL;
    224        const unsigned char *secondData = NULL;
    225 
    226        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Equals");
    227        PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult);
    228 
    229        /* test that firstObj is a OcspResponse */
    230        PKIX_CHECK(pkix_CheckType(firstObj, PKIX_OCSPRESPONSE_TYPE, plContext),
    231                    PKIX_FIRSTOBJARGUMENTNOTANOCSPRESPONSE);
    232 
    233        /*
    234         * Since we know firstObj is a OcspResponse, if both references are
    235         * identical, they must be equal
    236         */
    237        if (firstObj == secondObj){
    238                *pResult = PKIX_TRUE;
    239                goto cleanup;
    240        }
    241 
    242        /*
    243         * If secondObj isn't a OcspResponse, we don't throw an error.
    244         * We simply return a Boolean result of FALSE
    245         */
    246        *pResult = PKIX_FALSE;
    247        PKIX_CHECK(PKIX_PL_Object_GetType(secondObj, &secondType, plContext),
    248                PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
    249        if (secondType != PKIX_OCSPRESPONSE_TYPE) {
    250                goto cleanup;
    251        }
    252 
    253        rsp1 = (PKIX_PL_OcspResponse *)firstObj;
    254        rsp2 = (PKIX_PL_OcspResponse *)secondObj;
    255 
    256        /* If either lacks an encoded string, they cannot be compared */
    257        firstData = (const unsigned char *)rsp1->encodedResponse->data;
    258        secondData = (const unsigned char *)rsp2->encodedResponse->data;
    259        if ((firstData == NULL) || (secondData == NULL)) {
    260                goto cleanup;
    261        }
    262 
    263        firstLen = rsp1->encodedResponse->len;
    264 
    265        if (firstLen != rsp2->encodedResponse->len) {
    266                goto cleanup;
    267        }
    268 
    269        for (i = 0; i < firstLen; i++) {
    270                if (*firstData++ != *secondData++) {
    271                        goto cleanup;
    272                }
    273        }
    274 
    275        *pResult = PKIX_TRUE;
    276 
    277 cleanup:
    278 
    279        PKIX_RETURN(OCSPRESPONSE);
    280 }
    281 
    282 /*
    283 * FUNCTION: pkix_pl_OcspResponse_RegisterSelf
    284 * DESCRIPTION:
    285 *  Registers PKIX_OCSPRESPONSE_TYPE and its related functions with
    286 *  systemClasses[]
    287 * PARAMETERS:
    288 *  "plContext"
    289 *      Platform-specific context pointer.
    290 * THREAD SAFETY:
    291 *  Not Thread Safe - for performance and complexity reasons
    292 *
    293 *  Since this function is only called by PKIX_PL_Initialize, which should
    294 *  only be called once, it is acceptable that this function is not
    295 *  thread-safe.
    296 */
    297 PKIX_Error *
    298 pkix_pl_OcspResponse_RegisterSelf(void *plContext)
    299 {
    300        extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
    301        pkix_ClassTable_Entry *entry = &systemClasses[PKIX_OCSPRESPONSE_TYPE];
    302 
    303        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_RegisterSelf");
    304 
    305        entry->description = "OcspResponse";
    306        entry->typeObjectSize = sizeof(PKIX_PL_OcspResponse);
    307        entry->destructor = pkix_pl_OcspResponse_Destroy;
    308        entry->equalsFunction = pkix_pl_OcspResponse_Equals;
    309        entry->hashcodeFunction = pkix_pl_OcspResponse_Hashcode;
    310        entry->duplicateFunction = pkix_duplicateImmutable;
    311 
    312        PKIX_RETURN(OCSPRESPONSE);
    313 }
    314 
    315 /* --Public-Functions------------------------------------------------------- */
    316 
    317 /*
    318 * FUNCTION: pkix_pl_OcspResponse_Create
    319 * DESCRIPTION:
    320 *
    321 *  This function transmits the OcspRequest pointed to by "request" and obtains
    322 *  an OcspResponse, which it stores at "pOcspResponse". If the HTTPClient
    323 *  supports non-blocking I/O this function may store a non-NULL value at
    324 *  "pNBIOContext" (the WOULDBLOCK condition). In that case the caller should
    325 *  make a subsequent call with the same value in "pNBIOContext" and
    326 *  "pOcspResponse" to resume the operation. Additional WOULDBLOCK returns may
    327 *  occur; the caller should persist until a return occurs with NULL stored at
    328 *  "pNBIOContext".
    329 *
    330 *  If a SEC_HttpClientFcn "responder" is supplied, it is used as the client
    331 *  to which the OCSP query is sent. If none is supplied, the default responder
    332 *  is used.
    333 *
    334 *  If an OcspResponse_VerifyCallback "verifyFcn" is supplied, it is used to
    335 *  verify the Cert received from the responder as the signer. If none is
    336 *  supplied, the default verification function is used.
    337 *
    338 *  The contents of "request" are ignored on calls subsequent to a WOULDBLOCK
    339 *  return, and the caller is permitted to supply NULL.
    340 *
    341 * PARAMETERS
    342 *  "request"
    343 *      Address of the OcspRequest for which a response is desired.
    344 *  "httpMethod"
    345 *      GET or POST
    346 *  "responder"
    347 *      Address, if non-NULL, of the SEC_HttpClientFcn to be sent the OCSP
    348 *      query.
    349 *  "verifyFcn"
    350 *      Address, if non-NULL, of the OcspResponse_VerifyCallback function to be
    351 *      used to verify the Cert of the OCSP responder.
    352 *  "pNBIOContext"
    353 *      Address at which platform-dependent information is stored for handling
    354 *      of non-blocking I/O. Must be non-NULL.
    355 *  "pOcspResponse"
    356 *      The address where the created OcspResponse is stored. Must be non-NULL.
    357 *  "plContext"
    358 *      Platform-specific context pointer.
    359 * THREAD SAFETY:
    360 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    361 * RETURNS:
    362 *  Returns NULL if the function succeeds.
    363 *  Returns an OcspResponse Error if the function fails in a non-fatal way.
    364 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    365 */
    366 PKIX_Error *
    367 pkix_pl_OcspResponse_Create(
    368        PKIX_PL_OcspRequest *request,
    369        const char *httpMethod,
    370        void *responder,
    371        PKIX_PL_VerifyCallback verifyFcn,
    372        void **pNBIOContext,
    373        PKIX_PL_OcspResponse **pResponse,
    374        void *plContext)
    375 {
    376        void *nbioContext = NULL;
    377        PKIX_PL_OcspResponse *ocspResponse = NULL;
    378        const SEC_HttpClientFcn *httpClient = NULL;
    379        const SEC_HttpClientFcnV1 *hcv1 = NULL;
    380        SECStatus rv = SECFailure;
    381        char *location = NULL;
    382        char *hostname = NULL;
    383        char *path = NULL;
    384        char *responseContentType = NULL;
    385        PRUint16 port = 0;
    386        SEC_HTTP_SERVER_SESSION serverSession = NULL;
    387        SEC_HTTP_REQUEST_SESSION sessionRequest = NULL;
    388        SECItem *encodedRequest = NULL;
    389        PRUint16 responseCode = 0;
    390        char *responseData = NULL;
    391 
    392        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Create");
    393        PKIX_NULLCHECK_TWO(pNBIOContext, pResponse);
    394 
    395 if (!strcmp(httpMethod, "GET") && !strcmp(httpMethod, "POST")) {
    396 	PKIX_ERROR(PKIX_INVALIDOCSPHTTPMETHOD);
    397 }
    398 
    399        nbioContext = *pNBIOContext;
    400        *pNBIOContext = NULL;
    401 
    402        if (nbioContext != NULL) {
    403 
    404                ocspResponse = *pResponse;
    405                PKIX_NULLCHECK_ONE(ocspResponse);
    406 
    407                httpClient = ocspResponse->httpClient;
    408                serverSession = ocspResponse->serverSession;
    409                sessionRequest = ocspResponse->sessionRequest;
    410                PKIX_NULLCHECK_THREE(httpClient, serverSession, sessionRequest);
    411 
    412        } else {
    413                PKIX_UInt32 timeout =
    414                    ((PKIX_PL_NssContext*)plContext)->timeoutSeconds;
    415 
    416                PKIX_NULLCHECK_ONE(request);
    417 
    418                PKIX_CHECK(pkix_pl_OcspRequest_GetEncoded
    419                        (request, &encodedRequest, plContext),
    420                        PKIX_OCSPREQUESTGETENCODEDFAILED);
    421 
    422                /* prepare initial message to HTTPClient */
    423 
    424                /* Is there a default responder and is it enabled? */
    425                if (responder) {
    426                    httpClient = (const SEC_HttpClientFcn *)responder;
    427                } else {
    428                    httpClient = SEC_GetRegisteredHttpClient();
    429                }
    430 
    431                if (httpClient && (httpClient->version == 1)) {
    432 		char *fullGetPath = NULL;
    433 		const char *sessionPath = NULL;
    434 		PRBool usePOST = !strcmp(httpMethod, "POST");
    435 
    436                        hcv1 = &(httpClient->fcnTable.ftable1);
    437 
    438                        PKIX_CHECK(pkix_pl_OcspRequest_GetLocation
    439                                (request, &location, plContext),
    440                                PKIX_OCSPREQUESTGETLOCATIONFAILED);
    441 
    442                        /* parse location -> hostname, port, path */    
    443                        rv = CERT_ParseURL(location, &hostname, &port, &path);
    444                        if (rv == SECFailure || hostname == NULL || path == NULL) {
    445                                PKIX_ERROR(PKIX_URLPARSINGFAILED);
    446                        }
    447 
    448                        rv = (*hcv1->createSessionFcn)(hostname, port,
    449                                                       &serverSession);
    450                        if (rv != SECSuccess) {
    451                                PKIX_ERROR(PKIX_OCSPSERVERERROR);
    452                        }       
    453 
    454 		if (usePOST) {
    455 			sessionPath = path;
    456 		} else {
    457 			/* calculate, are we allowed to use GET? */
    458 			enum { max_get_request_size = 255 }; /* defined by RFC2560 */
    459 			char b64ReqBuf[max_get_request_size+1];
    460 			size_t base64size;
    461 			size_t slashLengthIfNeeded = 0;
    462 			size_t pathLength;
    463 			PRInt32 urlEncodedBufLength;
    464 			size_t getURLLength;
    465 			char *walkOutput = NULL;
    466 
    467 			pathLength = strlen(path);
    468 			if (path[pathLength-1] != '/') {
    469 				slashLengthIfNeeded = 1;
    470 			}
    471 			base64size = (((encodedRequest->len +2)/3) * 4);
    472 			if (base64size > max_get_request_size) {
    473 				PKIX_ERROR(PKIX_OCSPGETREQUESTTOOBIG);
    474 			}
    475 			memset(b64ReqBuf, 0, sizeof(b64ReqBuf));
    476 			PL_Base64Encode((const char *)encodedRequest->data, encodedRequest->len, b64ReqBuf);
    477 			urlEncodedBufLength = ocsp_UrlEncodeBase64Buf(b64ReqBuf, NULL);
    478 			getURLLength = pathLength + urlEncodedBufLength + slashLengthIfNeeded;
    479 			fullGetPath = (char*)PORT_Alloc(getURLLength);
    480 			if (!fullGetPath) {
    481 				PKIX_ERROR(PKIX_OUTOFMEMORY);
    482 			}
    483 			strcpy(fullGetPath, path);
    484 			walkOutput = fullGetPath + pathLength;
    485 			if (walkOutput > fullGetPath && slashLengthIfNeeded) {
    486 				strcpy(walkOutput, "/");
    487 				++walkOutput;
    488 			}
    489 			ocsp_UrlEncodeBase64Buf(b64ReqBuf, walkOutput);
    490 			sessionPath = fullGetPath;
    491 		}
    492 
    493                        rv = (*hcv1->createFcn)(serverSession, "http",
    494                                                sessionPath, httpMethod,
    495                                                PR_SecondsToInterval(timeout),
    496                                                &sessionRequest);
    497 		sessionPath = NULL;
    498 		if (fullGetPath) {
    499 			PORT_Free(fullGetPath);
    500 			fullGetPath = NULL;
    501 		}
    502 		
    503                        if (rv != SECSuccess) {
    504                                PKIX_ERROR(PKIX_OCSPSERVERERROR);
    505                        }       
    506 
    507 		if (usePOST) {
    508 			rv = (*hcv1->setPostDataFcn)(sessionRequest,
    509 						  (char *)encodedRequest->data,
    510 						  encodedRequest->len,
    511 						  "application/ocsp-request");
    512 			if (rv != SECSuccess) {
    513 				PKIX_ERROR(PKIX_OCSPSERVERERROR);
    514 			}
    515 		}
    516 
    517                        /* create a PKIX_PL_OcspResponse object */
    518                        PKIX_CHECK(PKIX_PL_Object_Alloc
    519                                    (PKIX_OCSPRESPONSE_TYPE,
    520                                    sizeof (PKIX_PL_OcspResponse),
    521                                    (PKIX_PL_Object **)&ocspResponse,
    522                                    plContext),
    523                                    PKIX_COULDNOTCREATEOBJECT);
    524 
    525                        PKIX_INCREF(request);
    526                        ocspResponse->request = request;
    527                        ocspResponse->httpClient = httpClient;
    528                        ocspResponse->serverSession = serverSession;
    529                        serverSession = NULL;
    530                        ocspResponse->sessionRequest = sessionRequest;
    531                        sessionRequest = NULL;
    532                        ocspResponse->verifyFcn = verifyFcn;
    533                        ocspResponse->handle = CERT_GetDefaultCertDB();
    534                        ocspResponse->encodedResponse = NULL;
    535                        ocspResponse->arena = NULL;
    536                        ocspResponse->producedAt = 0;
    537                        ocspResponse->producedAtDate = NULL;
    538                        ocspResponse->pkixSignerCert = NULL;
    539                        ocspResponse->nssOCSPResponse = NULL;
    540                        ocspResponse->signerCert = NULL;
    541                }
    542        }
    543 
    544        /* begin or resume IO to HTTPClient */
    545        if (httpClient && (httpClient->version == 1)) {
    546                PRUint32 responseDataLen = 
    547                   ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
    548 
    549                hcv1 = &(httpClient->fcnTable.ftable1);
    550 
    551                rv = (*hcv1->trySendAndReceiveFcn)(ocspResponse->sessionRequest,
    552                        (PRPollDesc **)&nbioContext,
    553                        &responseCode,
    554                        (const char **)&responseContentType,
    555                        NULL,   /* responseHeaders */
    556                        (const char **)&responseData,
    557                        &responseDataLen);
    558 
    559                if (rv != SECSuccess) {
    560                        PKIX_ERROR(PKIX_OCSPSERVERERROR);
    561                }
    562                /* responseContentType is a pointer to the null-terminated
    563                 * string returned by httpclient. Memory allocated for context
    564                 * type will be freed with freeing of the HttpClient struct. */
    565                if (PORT_Strcasecmp(responseContentType, 
    566                                   "application/ocsp-response")) {
    567                       PKIX_ERROR(PKIX_OCSPSERVERERROR);
    568                }
    569                if (nbioContext != NULL) {
    570                        *pNBIOContext = nbioContext;
    571                        goto cleanup;
    572                }
    573                if (responseCode != 200) {
    574                        PKIX_ERROR(PKIX_OCSPBADHTTPRESPONSE);
    575                }
    576                ocspResponse->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    577                if (ocspResponse->arena == NULL) {
    578                        PKIX_ERROR(PKIX_OUTOFMEMORY);
    579                }
    580                ocspResponse->encodedResponse = SECITEM_AllocItem
    581                        (ocspResponse->arena, NULL, responseDataLen);
    582                if (ocspResponse->encodedResponse == NULL) {
    583                        PKIX_ERROR(PKIX_OUTOFMEMORY);
    584                }
    585                PORT_Memcpy(ocspResponse->encodedResponse->data,
    586                            responseData, responseDataLen);
    587        }
    588        *pResponse = ocspResponse;
    589        ocspResponse = NULL;
    590 
    591 cleanup:
    592 
    593        if (path != NULL) {
    594            PORT_Free(path);
    595        }
    596        if (hostname != NULL) {
    597            PORT_Free(hostname);
    598        }
    599        if (ocspResponse) {
    600            PKIX_DECREF(ocspResponse);
    601        }
    602        if (serverSession) {
    603            hcv1->freeSessionFcn(serverSession);
    604        }
    605        if (sessionRequest) {
    606            hcv1->freeFcn(sessionRequest);
    607        }
    608 
    609        PKIX_RETURN(OCSPRESPONSE);
    610 }
    611 
    612 /*
    613 * FUNCTION: pkix_pl_OcspResponse_Decode
    614 * DESCRIPTION:
    615 *
    616 *  This function decodes the DER data contained in the OcspResponse pointed to
    617 *  by "response", storing PKIX_TRUE at "pPassed" if the decoding was
    618 *  successful, and PKIX_FALSE otherwise.
    619 *
    620 * PARAMETERS
    621 *  "response"
    622 *      The address of the OcspResponse whose DER data is to be decoded. Must
    623 *      be non-NULL.
    624 *  "pPassed"
    625 *      Address at which the Boolean result is stored. Must be non-NULL.
    626 *  "pReturnCode"
    627 *      Address at which the SECErrorCodes result is stored. Must be non-NULL.
    628 *  "plContext"
    629 *      Platform-specific context pointer.
    630 * THREAD SAFETY:
    631 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    632 * RETURNS:
    633 *  Returns NULL if the function succeeds.
    634 *  Returns an OcspResponse Error if the function fails in a non-fatal way.
    635 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    636 */
    637 
    638 PKIX_Error *
    639 pkix_pl_OcspResponse_Decode(
    640        PKIX_PL_OcspResponse *response,
    641        PKIX_Boolean *pPassed,
    642        SECErrorCodes *pReturnCode,
    643        void *plContext)
    644 {
    645 
    646        PKIX_ENTER(OCSPRESPONSE, "PKIX_PL_OcspResponse_Decode");
    647        PKIX_NULLCHECK_TWO(response, response->encodedResponse);
    648 
    649        response->nssOCSPResponse =
    650            CERT_DecodeOCSPResponse(response->encodedResponse);
    651 
    652 if (response->nssOCSPResponse != NULL) {
    653                *pPassed = PKIX_TRUE;
    654                *pReturnCode = 0;
    655        } else {
    656                *pPassed = PKIX_FALSE;
    657                *pReturnCode = PORT_GetError();
    658        }
    659 
    660        PKIX_RETURN(OCSPRESPONSE);
    661 }
    662 
    663 /*
    664 * FUNCTION: pkix_pl_OcspResponse_GetStatus
    665 * DESCRIPTION:
    666 *
    667 *  This function checks the response status of the OcspResponse pointed to
    668 *  by "response", storing PKIX_TRUE at "pPassed" if the responder understood
    669 *  the request and considered it valid, and PKIX_FALSE otherwise.
    670 *
    671 * PARAMETERS
    672 *  "response"
    673 *      The address of the OcspResponse whose status is to be retrieved. Must
    674 *      be non-NULL.
    675 *  "pPassed"
    676 *      Address at which the Boolean result is stored. Must be non-NULL.
    677 *  "plContext"
    678 *      Platform-specific context pointer.
    679 * THREAD SAFETY:
    680 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    681 * RETURNS:
    682 *  Returns NULL if the function succeeds.
    683 *  Returns an OcspResponse Error if the function fails in a non-fatal way.
    684 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    685 */
    686 
    687 PKIX_Error *
    688 pkix_pl_OcspResponse_GetStatus(
    689        PKIX_PL_OcspResponse *response,
    690        PKIX_Boolean *pPassed,
    691        SECErrorCodes *pReturnCode,
    692        void *plContext)
    693 {
    694        SECStatus rv = SECFailure;
    695 
    696        PKIX_ENTER(OCSPRESPONSE, "PKIX_PL_OcspResponse_GetStatus");
    697        PKIX_NULLCHECK_FOUR(response, response->nssOCSPResponse, pPassed, pReturnCode);
    698 
    699        rv = CERT_GetOCSPResponseStatus(response->nssOCSPResponse);
    700 
    701 if (rv == SECSuccess) {
    702                *pPassed = PKIX_TRUE;
    703                *pReturnCode = 0;
    704        } else {
    705                *pPassed = PKIX_FALSE;
    706                *pReturnCode = PORT_GetError();
    707        }
    708 
    709        PKIX_RETURN(OCSPRESPONSE);
    710 }
    711 
    712 
    713 static PKIX_Error*
    714 pkix_pl_OcspResponse_VerifyResponse(
    715        PKIX_PL_OcspResponse *response,
    716        PKIX_ProcessingParams *procParams,
    717        SECCertUsage certUsage,
    718        void **state,
    719        PKIX_BuildResult **buildResult,
    720        void **pNBIOContext,
    721        void *plContext)
    722 {
    723    SECStatus rv = SECFailure;
    724 
    725    PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_VerifyResponse");
    726 
    727    if (response->verifyFcn != NULL) {
    728        void *lplContext = NULL;
    729        
    730        PKIX_CHECK(
    731            PKIX_PL_NssContext_Create(((SECCertificateUsage)1) << certUsage,
    732                                      PKIX_FALSE, NULL, &lplContext),
    733            PKIX_NSSCONTEXTCREATEFAILED);
    734 
    735        PKIX_CHECK(
    736            (response->verifyFcn)((PKIX_PL_Object*)response->pkixSignerCert,
    737                                  NULL, response->producedAtDate,
    738                                  procParams, pNBIOContext,
    739                                  state, buildResult,
    740                                  NULL, lplContext),
    741            PKIX_CERTVERIFYKEYUSAGEFAILED);
    742        rv = SECSuccess;
    743    } else {
    744        /* checkSig is !isRoot */
    745        PRBool checkSig = response->signerCert->isRoot ? PR_FALSE : PR_TRUE;
    746        rv = CERT_VerifyCert(response->handle, response->signerCert, checkSig,
    747                             certUsage, response->producedAt, NULL, NULL);
    748        if (rv != SECSuccess) {
    749            PKIX_ERROR(PKIX_CERTVERIFYKEYUSAGEFAILED);
    750        }
    751    }
    752 
    753 cleanup:
    754    if (rv != SECSuccess) {
    755        PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
    756    }
    757 
    758    PKIX_RETURN(OCSPRESPONSE);
    759 }
    760 
    761 /*
    762 * FUNCTION: pkix_pl_OcspResponse_VerifySignature
    763 * DESCRIPTION:
    764 *
    765 *  This function verifies the ocspResponse signature field in the OcspResponse
    766 *  pointed to by "response", storing PKIX_TRUE at "pPassed" if verification
    767 *  is successful and PKIX_FALSE otherwise. If verification is unsuccessful an
    768 *  error code (an enumeration of type SECErrorCodes) is stored at *pReturnCode.
    769 *
    770 * PARAMETERS
    771 *  "response"
    772 *      The address of the OcspResponse whose signature field is to be
    773 *      retrieved. Must be non-NULL.
    774 *  "cert"
    775 *      The address of the Cert for which the OCSP query was made. Must be
    776 *      non-NULL.
    777 *  "procParams"
    778 *      Address of ProcessingParams used to initialize the ExpirationChecker
    779 *      and TargetCertChecker. Must be non-NULL.
    780 *  "pPassed"
    781 *      Address at which the Boolean result is stored. Must be non-NULL.
    782 *  "pNBIOContext"
    783 *      Address at which the NBIOContext is stored indicating whether the
    784 *      checking is complete. Must be non-NULL.
    785 *  "plContext"
    786 *      Platform-specific context pointer.
    787 * THREAD SAFETY:
    788 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    789 * RETURNS:
    790 *  Returns NULL if the function succeeds.
    791 *  Returns an OcspResponse Error if the function fails in a non-fatal way.
    792 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    793 */
    794 PKIX_Error *
    795 pkix_pl_OcspResponse_VerifySignature(
    796        PKIX_PL_OcspResponse *response,
    797        PKIX_PL_Cert *cert,
    798        PKIX_ProcessingParams *procParams,
    799        PKIX_Boolean *pPassed,
    800        void **pNBIOContext,
    801        void *plContext)
    802 {
    803        SECStatus rv = SECFailure;
    804        CERTOCSPResponse *nssOCSPResponse = NULL;
    805        CERTCertificate *issuerCert = NULL;
    806        PKIX_BuildResult *buildResult = NULL;
    807        void *nbio = NULL;
    808        void *state = NULL;
    809 
    810        ocspSignature *signature = NULL;
    811        ocspResponseData *tbsData = NULL;
    812        SECItem *tbsResponseDataDER = NULL;
    813 
    814 
    815        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_VerifySignature");
    816        PKIX_NULLCHECK_FOUR(response, cert, pPassed,  pNBIOContext);
    817 
    818        nbio = *pNBIOContext;
    819        *pNBIOContext = NULL;
    820 
    821        nssOCSPResponse = response->nssOCSPResponse;
    822        if (nssOCSPResponse == NULL) {
    823            PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
    824            goto cleanup;
    825        }
    826 
    827        tbsData =
    828            ocsp_GetResponseData(nssOCSPResponse, &tbsResponseDataDER);
    829        
    830        signature = ocsp_GetResponseSignature(nssOCSPResponse);
    831 
    832 
    833        /* Are we resuming after a WOULDBLOCK response? */
    834        if (nbio == NULL) {
    835            /* No, this is a new query */
    836 
    837            issuerCert = CERT_FindCertIssuer(cert->nssCert, PR_Now(),
    838                                             certUsageAnyCA);
    839            
    840            /*
    841             * If this signature has already gone through verification,
    842             * just return the cached result.
    843             */
    844            if (signature->wasChecked) {
    845                if (signature->status == SECSuccess) {
    846                    response->signerCert =
    847                        CERT_DupCertificate(signature->cert);
    848                } else {
    849                    PORT_SetError(signature->failureReason);
    850                    goto cleanup;
    851                }
    852            }
    853            
    854            response->signerCert = 
    855                ocsp_GetSignerCertificate(response->handle, tbsData,
    856                                          signature, issuerCert);
    857            
    858            if (response->signerCert == NULL) {
    859                if (PORT_GetError() == SEC_ERROR_UNKNOWN_CERT) {
    860                    /* Make the error a little more specific. */
    861                    PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
    862                }
    863                goto cleanup;
    864            }            
    865            PKIX_CHECK( 
    866                PKIX_PL_Cert_CreateFromCERTCertificate(response->signerCert,
    867                                                       &(response->pkixSignerCert),
    868                                                       plContext),
    869                PKIX_CERTCREATEWITHNSSCERTFAILED);
    870            
    871            /*
    872             * We could mark this true at the top of this function, or
    873             * always below at "finish", but if the problem was just that
    874             * we could not find the signer's cert, leave that as if the
    875             * signature hasn't been checked. Maybe a subsequent call will
    876             * have better luck.
    877             */
    878            signature->wasChecked = PR_TRUE;
    879            
    880            /*
    881             * We are about to verify the signer certificate; we need to
    882             * specify *when* that certificate must be valid -- for our
    883             * purposes we expect it to be valid when the response was
    884             * signed. The value of "producedAt" is the signing time.
    885             */
    886            rv = DER_GeneralizedTimeToTime(&response->producedAt,
    887                                           &tbsData->producedAt);
    888            if (rv != SECSuccess) {
    889                PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
    890                goto cleanup;
    891            }
    892            
    893            /*
    894             * We need producedAtDate and pkixSignerCert if we are calling a
    895             * user-supplied verification function. Let's put their
    896             * creation before the code that gets repeated when
    897             * non-blocking I/O is used.
    898             */
    899            
    900            PKIX_CHECK(
    901                pkix_pl_Date_CreateFromPRTime((PRTime)response->producedAt,
    902                                              &(response->producedAtDate),
    903                                              plContext),
    904                PKIX_DATECREATEFROMPRTIMEFAILED);
    905            
    906 }
    907        
    908        /*
    909         * Just because we have a cert does not mean it is any good; check
    910         * it for validity, trust and usage. Use the caller-supplied
    911         * verification function, if one was supplied.
    912         */
    913        if (ocsp_CertIsOCSPDefaultResponder(response->handle,
    914                                            response->signerCert)) {
    915            rv = SECSuccess;
    916        } else {
    917            SECCertUsage certUsage;
    918            if (CERT_IsCACert(response->signerCert, NULL)) {
    919                certUsage = certUsageAnyCA;
    920            } else {
    921                certUsage = certUsageStatusResponder;
    922            }
    923            PKIX_CHECK_ONLY_FATAL(
    924                pkix_pl_OcspResponse_VerifyResponse(response, procParams,
    925                                                    certUsage, &state,
    926                                                    &buildResult, &nbio,
    927                                                    plContext),
    928                PKIX_CERTVERIFYKEYUSAGEFAILED);
    929            if (pkixTempErrorReceived) {
    930                rv = SECFailure;
    931                goto cleanup;
    932            }
    933            if (nbio != NULL) {
    934                *pNBIOContext = nbio;
    935                goto cleanup;
    936            }            
    937        }
    938 
    939        rv = ocsp_VerifyResponseSignature(response->signerCert, signature,
    940                                          tbsResponseDataDER, NULL);
    941        
    942 cleanup:
    943        if (rv == SECSuccess) {
    944            *pPassed = PKIX_TRUE;
    945        } else {
    946            *pPassed = PKIX_FALSE;
    947        }
    948        
    949        if (signature) {
    950            if (signature->wasChecked) {
    951                signature->status = rv;
    952            }
    953            
    954            if (rv != SECSuccess) {
    955                signature->failureReason = PORT_GetError();
    956                if (response->signerCert != NULL) {
    957                    CERT_DestroyCertificate(response->signerCert);
    958                    response->signerCert = NULL;
    959                }
    960            } else {
    961                /* Save signer's certificate in signature. */
    962                signature->cert = CERT_DupCertificate(response->signerCert);
    963            }
    964        }
    965 
    966 if (issuerCert)
    967     CERT_DestroyCertificate(issuerCert);
    968        
    969        PKIX_RETURN(OCSPRESPONSE);
    970 }
    971 
    972 /*
    973 * FUNCTION: pkix_pl_OcspResponse_GetStatusForCert
    974 * DESCRIPTION:
    975 *
    976 *  This function checks the revocation status of the Cert for which the
    977 *  OcspResponse was obtained, storing PKIX_TRUE at "pPassed" if the Cert has
    978 *  not been revoked and PKIX_FALSE otherwise.
    979 *
    980 * PARAMETERS
    981 *  "response"
    982 *      The address of the OcspResponse whose certificate status is to be
    983 *      retrieved. Must be non-NULL.
    984 *  "pPassed"
    985 *      Address at which the Boolean result is stored. Must be non-NULL.
    986 *  "pReturnCode"
    987 *      Address at which the SECErrorCodes result is stored. Must be non-NULL.
    988 *  "plContext"
    989 *      Platform-specific context pointer.
    990 * THREAD SAFETY:
    991 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    992 * RETURNS:
    993 *  Returns NULL if the function succeeds.
    994 *  Returns an OcspResponse Error if the function fails in a non-fatal way.
    995 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    996 */
    997 PKIX_Error *
    998 pkix_pl_OcspResponse_GetStatusForCert(
    999        PKIX_PL_OcspCertID *cid,
   1000        PKIX_PL_OcspResponse *response,
   1001        PKIX_Boolean allowCachingOfFailures,
   1002        PKIX_PL_Date *validity,
   1003        PKIX_Boolean *pPassed,
   1004        SECErrorCodes *pReturnCode,
   1005        void *plContext)
   1006 {
   1007        PRTime time = 0;
   1008        SECStatus rv = SECFailure;
   1009        CERTOCSPSingleResponse *single = NULL;
   1010 
   1011        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_GetStatusForCert");
   1012        PKIX_NULLCHECK_THREE(response, pPassed, pReturnCode);
   1013 
   1014        /*
   1015         * It is an error to call this function except following a successful
   1016         * return from pkix_pl_OcspResponse_VerifySignature, which would have
   1017         * set response->signerCert.
   1018         */
   1019        PKIX_NULLCHECK_TWO(response->signerCert, response->request);
   1020        PKIX_NULLCHECK_TWO(cid, cid->certID);
   1021 
   1022        if (validity != NULL) {
   1023            PKIX_Error *er = pkix_pl_Date_GetPRTime(validity, &time, plContext);
   1024            PKIX_DECREF(er);
   1025        }
   1026        if (!time) {
   1027            time = PR_Now();
   1028        }
   1029 
   1030        rv = ocsp_GetVerifiedSingleResponseForCertID(response->handle,
   1031                                                     response->nssOCSPResponse,
   1032                                                     cid->certID, 
   1033                                                     response->signerCert,
   1034                                                     time, &single);
   1035        if (rv == SECSuccess) {
   1036                /*
   1037                 * Check whether the status says revoked, and if so 
   1038                 * how that compares to the time value passed into this routine.
   1039                 */
   1040                rv = ocsp_CertHasGoodStatus(single->certStatus, time);
   1041        }
   1042 
   1043        if (rv == SECSuccess || allowCachingOfFailures) {
   1044                /* allowed to update the cache */
   1045                PRBool certIDWasConsumed = PR_FALSE;
   1046 
   1047                if (single) {
   1048                        ocsp_CacheSingleResponse(cid->certID,single,
   1049                                                 &certIDWasConsumed);
   1050                } else {
   1051                        cert_RememberOCSPProcessingFailure(cid->certID,
   1052                                                           &certIDWasConsumed);
   1053                }
   1054 
   1055                if (certIDWasConsumed) {
   1056                        cid->certID = NULL;
   1057                }
   1058        }
   1059 
   1060 if (rv == SECSuccess) {
   1061                *pPassed = PKIX_TRUE;
   1062                *pReturnCode = 0;
   1063        } else {
   1064                *pPassed = PKIX_FALSE;
   1065                *pReturnCode = PORT_GetError();
   1066        }
   1067 
   1068        PKIX_RETURN(OCSPRESPONSE);
   1069 }