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 }