| OLD | NEW |
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public | 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 | 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/. */ | 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 4 /* | 4 /* |
| 5 * pkix_pl_ocspresponse.c | 5 * pkix_pl_ocspresponse.c |
| 6 * | 6 * |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 #include "pkix_pl_ocspresponse.h" | 9 #include "pkix_pl_ocspresponse.h" |
| 10 | 10 |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 * If an OcspResponse_VerifyCallback "verifyFcn" is supplied, it is used to | 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 | 335 * verify the Cert received from the responder as the signer. If none is |
| 336 * supplied, the default verification function is used. | 336 * supplied, the default verification function is used. |
| 337 * | 337 * |
| 338 * The contents of "request" are ignored on calls subsequent to a WOULDBLOCK | 338 * The contents of "request" are ignored on calls subsequent to a WOULDBLOCK |
| 339 * return, and the caller is permitted to supply NULL. | 339 * return, and the caller is permitted to supply NULL. |
| 340 * | 340 * |
| 341 * PARAMETERS | 341 * PARAMETERS |
| 342 * "request" | 342 * "request" |
| 343 * Address of the OcspRequest for which a response is desired. | 343 * Address of the OcspRequest for which a response is desired. |
| 344 * "httpMethod" |
| 345 * GET or POST |
| 344 * "responder" | 346 * "responder" |
| 345 * Address, if non-NULL, of the SEC_HttpClientFcn to be sent the OCSP | 347 * Address, if non-NULL, of the SEC_HttpClientFcn to be sent the OCSP |
| 346 * query. | 348 * query. |
| 347 * "verifyFcn" | 349 * "verifyFcn" |
| 348 * Address, if non-NULL, of the OcspResponse_VerifyCallback function to be | 350 * Address, if non-NULL, of the OcspResponse_VerifyCallback function to be |
| 349 * used to verify the Cert of the OCSP responder. | 351 * used to verify the Cert of the OCSP responder. |
| 350 * "pNBIOContext" | 352 * "pNBIOContext" |
| 351 * Address at which platform-dependent information is stored for handling | 353 * Address at which platform-dependent information is stored for handling |
| 352 * of non-blocking I/O. Must be non-NULL. | 354 * of non-blocking I/O. Must be non-NULL. |
| 353 * "pOcspResponse" | 355 * "pOcspResponse" |
| 354 * The address where the created OcspResponse is stored. Must be non-NULL. | 356 * The address where the created OcspResponse is stored. Must be non-NULL. |
| 355 * "plContext" | 357 * "plContext" |
| 356 * Platform-specific context pointer. | 358 * Platform-specific context pointer. |
| 357 * THREAD SAFETY: | 359 * THREAD SAFETY: |
| 358 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | 360 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
| 359 * RETURNS: | 361 * RETURNS: |
| 360 * Returns NULL if the function succeeds. | 362 * Returns NULL if the function succeeds. |
| 361 * Returns an OcspResponse Error if the function fails in a non-fatal way. | 363 * Returns an OcspResponse Error if the function fails in a non-fatal way. |
| 362 * Returns a Fatal Error if the function fails in an unrecoverable way. | 364 * Returns a Fatal Error if the function fails in an unrecoverable way. |
| 363 */ | 365 */ |
| 364 PKIX_Error * | 366 PKIX_Error * |
| 365 pkix_pl_OcspResponse_Create( | 367 pkix_pl_OcspResponse_Create( |
| 366 PKIX_PL_OcspRequest *request, | 368 PKIX_PL_OcspRequest *request, |
| 369 const char *httpMethod, |
| 367 void *responder, | 370 void *responder, |
| 368 PKIX_PL_VerifyCallback verifyFcn, | 371 PKIX_PL_VerifyCallback verifyFcn, |
| 369 void **pNBIOContext, | 372 void **pNBIOContext, |
| 370 PKIX_PL_OcspResponse **pResponse, | 373 PKIX_PL_OcspResponse **pResponse, |
| 371 void *plContext) | 374 void *plContext) |
| 372 { | 375 { |
| 373 void *nbioContext = NULL; | 376 void *nbioContext = NULL; |
| 374 PKIX_PL_OcspResponse *ocspResponse = NULL; | 377 PKIX_PL_OcspResponse *ocspResponse = NULL; |
| 375 const SEC_HttpClientFcn *httpClient = NULL; | 378 const SEC_HttpClientFcn *httpClient = NULL; |
| 376 const SEC_HttpClientFcnV1 *hcv1 = NULL; | 379 const SEC_HttpClientFcnV1 *hcv1 = NULL; |
| 377 SECStatus rv = SECFailure; | 380 SECStatus rv = SECFailure; |
| 378 char *location = NULL; | 381 char *location = NULL; |
| 379 char *hostname = NULL; | 382 char *hostname = NULL; |
| 380 char *path = NULL; | 383 char *path = NULL; |
| 381 char *responseContentType = NULL; | 384 char *responseContentType = NULL; |
| 382 PRUint16 port = 0; | 385 PRUint16 port = 0; |
| 383 SEC_HTTP_SERVER_SESSION serverSession = NULL; | 386 SEC_HTTP_SERVER_SESSION serverSession = NULL; |
| 384 SEC_HTTP_REQUEST_SESSION sessionRequest = NULL; | 387 SEC_HTTP_REQUEST_SESSION sessionRequest = NULL; |
| 385 SECItem *encodedRequest = NULL; | 388 SECItem *encodedRequest = NULL; |
| 386 PRUint16 responseCode = 0; | 389 PRUint16 responseCode = 0; |
| 387 char *responseData = NULL; | 390 char *responseData = NULL; |
| 388 | 391 |
| 389 PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Create"); | 392 PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Create"); |
| 390 PKIX_NULLCHECK_TWO(pNBIOContext, pResponse); | 393 PKIX_NULLCHECK_TWO(pNBIOContext, pResponse); |
| 391 | 394 |
| 395 if (!strcmp(httpMethod, "GET") && !strcmp(httpMethod, "POST")) { |
| 396 PKIX_ERROR(PKIX_INVALIDOCSPHTTPMETHOD); |
| 397 } |
| 398 |
| 392 nbioContext = *pNBIOContext; | 399 nbioContext = *pNBIOContext; |
| 393 *pNBIOContext = NULL; | 400 *pNBIOContext = NULL; |
| 394 | 401 |
| 395 if (nbioContext != NULL) { | 402 if (nbioContext != NULL) { |
| 396 | 403 |
| 397 ocspResponse = *pResponse; | 404 ocspResponse = *pResponse; |
| 398 PKIX_NULLCHECK_ONE(ocspResponse); | 405 PKIX_NULLCHECK_ONE(ocspResponse); |
| 399 | 406 |
| 400 httpClient = ocspResponse->httpClient; | 407 httpClient = ocspResponse->httpClient; |
| 401 serverSession = ocspResponse->serverSession; | 408 serverSession = ocspResponse->serverSession; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 415 /* prepare initial message to HTTPClient */ | 422 /* prepare initial message to HTTPClient */ |
| 416 | 423 |
| 417 /* Is there a default responder and is it enabled? */ | 424 /* Is there a default responder and is it enabled? */ |
| 418 if (responder) { | 425 if (responder) { |
| 419 httpClient = (const SEC_HttpClientFcn *)responder; | 426 httpClient = (const SEC_HttpClientFcn *)responder; |
| 420 } else { | 427 } else { |
| 421 httpClient = SEC_GetRegisteredHttpClient(); | 428 httpClient = SEC_GetRegisteredHttpClient(); |
| 422 } | 429 } |
| 423 | 430 |
| 424 if (httpClient && (httpClient->version == 1)) { | 431 if (httpClient && (httpClient->version == 1)) { |
| 432 char *fullGetPath = NULL; |
| 433 const char *sessionPath = NULL; |
| 434 PRBool usePOST = !strcmp(httpMethod, "POST"); |
| 425 | 435 |
| 426 hcv1 = &(httpClient->fcnTable.ftable1); | 436 hcv1 = &(httpClient->fcnTable.ftable1); |
| 427 | 437 |
| 428 PKIX_CHECK(pkix_pl_OcspRequest_GetLocation | 438 PKIX_CHECK(pkix_pl_OcspRequest_GetLocation |
| 429 (request, &location, plContext), | 439 (request, &location, plContext), |
| 430 PKIX_OCSPREQUESTGETLOCATIONFAILED); | 440 PKIX_OCSPREQUESTGETLOCATIONFAILED); |
| 431 | 441 |
| 432 /* parse location -> hostname, port, path */ | 442 /* parse location -> hostname, port, path */ |
| 433 rv = CERT_ParseURL(location, &hostname, &port, &path); | 443 rv = CERT_ParseURL(location, &hostname, &port, &path); |
| 434 if (rv == SECFailure || hostname == NULL || path == NULL
) { | 444 if (rv == SECFailure || hostname == NULL || path == NULL
) { |
| 435 PKIX_ERROR(PKIX_URLPARSINGFAILED); | 445 PKIX_ERROR(PKIX_URLPARSINGFAILED); |
| 436 } | 446 } |
| 437 | 447 |
| 438 rv = (*hcv1->createSessionFcn)(hostname, port, | 448 rv = (*hcv1->createSessionFcn)(hostname, port, |
| 439 &serverSession); | 449 &serverSession); |
| 440 if (rv != SECSuccess) { | 450 if (rv != SECSuccess) { |
| 441 PKIX_ERROR(PKIX_OCSPSERVERERROR); | 451 PKIX_ERROR(PKIX_OCSPSERVERERROR); |
| 442 } | 452 } |
| 443 | 453 |
| 444 rv = (*hcv1->createFcn)(serverSession, "http", path, | 454 » » » if (usePOST) { |
| 445 "POST", | 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->da
ta, encodedRequest->len, b64ReqBuf); |
| 477 » » » » urlEncodedBufLength = ocsp_UrlEncodeBase64Buf(b6
4ReqBuf, 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 && slashLengthIfNee
ded) { |
| 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, |
| 446 PR_SecondsToInterval(timeout), | 495 PR_SecondsToInterval(timeout), |
| 447 &sessionRequest); | 496 &sessionRequest); |
| 497 sessionPath = NULL; |
| 498 if (fullGetPath) { |
| 499 PORT_Free(fullGetPath); |
| 500 fullGetPath = NULL; |
| 501 } |
| 502 |
| 448 if (rv != SECSuccess) { | 503 if (rv != SECSuccess) { |
| 449 PKIX_ERROR(PKIX_OCSPSERVERERROR); | 504 PKIX_ERROR(PKIX_OCSPSERVERERROR); |
| 450 } | 505 } |
| 451 | 506 |
| 452 rv = (*hcv1->setPostDataFcn)(sessionRequest, | 507 » » » if (usePOST) { |
| 453 (char *)encodedRequest->data, | 508 » » » » rv = (*hcv1->setPostDataFcn)(sessionRequest, |
| 454 encodedRequest->len, | 509 » » » » » » » (char *)encodedRequest
->data, |
| 455 "application/ocsp-request"); | 510 » » » » » » » encodedRequest->len, |
| 456 if (rv != SECSuccess) { | 511 » » » » » » » "application/ocsp-requ
est"); |
| 457 PKIX_ERROR(PKIX_OCSPSERVERERROR); | 512 » » » » if (rv != SECSuccess) { |
| 458 } | 513 » » » » » PKIX_ERROR(PKIX_OCSPSERVERERROR); |
| 514 » » » » } |
| 515 » » » } |
| 459 | 516 |
| 460 /* create a PKIX_PL_OcspResponse object */ | 517 /* create a PKIX_PL_OcspResponse object */ |
| 461 PKIX_CHECK(PKIX_PL_Object_Alloc | 518 PKIX_CHECK(PKIX_PL_Object_Alloc |
| 462 (PKIX_OCSPRESPONSE_TYPE, | 519 (PKIX_OCSPRESPONSE_TYPE, |
| 463 sizeof (PKIX_PL_OcspResponse), | 520 sizeof (PKIX_PL_OcspResponse), |
| 464 (PKIX_PL_Object **)&ocspResponse, | 521 (PKIX_PL_Object **)&ocspResponse, |
| 465 plContext), | 522 plContext), |
| 466 PKIX_COULDNOTCREATEOBJECT); | 523 PKIX_COULDNOTCREATEOBJECT); |
| 467 | 524 |
| 468 PKIX_INCREF(request); | 525 PKIX_INCREF(request); |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 790 PORT_SetError(signature->failureReason); | 847 PORT_SetError(signature->failureReason); |
| 791 goto cleanup; | 848 goto cleanup; |
| 792 } | 849 } |
| 793 } | 850 } |
| 794 | 851 |
| 795 response->signerCert = | 852 response->signerCert = |
| 796 ocsp_GetSignerCertificate(response->handle, tbsData, | 853 ocsp_GetSignerCertificate(response->handle, tbsData, |
| 797 signature, issuerCert); | 854 signature, issuerCert); |
| 798 | 855 |
| 799 if (response->signerCert == NULL) { | 856 if (response->signerCert == NULL) { |
| 800 PORT_SetError(SEC_ERROR_UNKNOWN_SIGNER); | 857 if (PORT_GetError() == SEC_ERROR_UNKNOWN_CERT) { |
| 858 /* Make the error a little more specific. */ |
| 859 PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT); |
| 860 } |
| 801 goto cleanup; | 861 goto cleanup; |
| 802 } | 862 } |
| 803 | |
| 804 PKIX_CHECK( | 863 PKIX_CHECK( |
| 805 PKIX_PL_Cert_CreateFromCERTCertificate(response->signerCert, | 864 PKIX_PL_Cert_CreateFromCERTCertificate(response->signerCert, |
| 806 &(response->pkixSignerCer
t), | 865 &(response->pkixSignerCer
t), |
| 807 plContext), | 866 plContext), |
| 808 PKIX_CERTCREATEWITHNSSCERTFAILED); | 867 PKIX_CERTCREATEWITHNSSCERTFAILED); |
| 809 | 868 |
| 810 /* | 869 /* |
| 811 * We could mark this true at the top of this function, or | 870 * We could mark this true at the top of this function, or |
| 812 * always below at "finish", but if the problem was just that | 871 * always below at "finish", but if the problem was just that |
| 813 * we could not find the signer's cert, leave that as if the | 872 * we could not find the signer's cert, leave that as if the |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 930 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | 989 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
| 931 * RETURNS: | 990 * RETURNS: |
| 932 * Returns NULL if the function succeeds. | 991 * Returns NULL if the function succeeds. |
| 933 * Returns an OcspResponse Error if the function fails in a non-fatal way. | 992 * Returns an OcspResponse Error if the function fails in a non-fatal way. |
| 934 * Returns a Fatal Error if the function fails in an unrecoverable way. | 993 * Returns a Fatal Error if the function fails in an unrecoverable way. |
| 935 */ | 994 */ |
| 936 PKIX_Error * | 995 PKIX_Error * |
| 937 pkix_pl_OcspResponse_GetStatusForCert( | 996 pkix_pl_OcspResponse_GetStatusForCert( |
| 938 PKIX_PL_OcspCertID *cid, | 997 PKIX_PL_OcspCertID *cid, |
| 939 PKIX_PL_OcspResponse *response, | 998 PKIX_PL_OcspResponse *response, |
| 999 PKIX_Boolean allowCachingOfFailures, |
| 940 PKIX_PL_Date *validity, | 1000 PKIX_PL_Date *validity, |
| 941 PKIX_Boolean *pPassed, | 1001 PKIX_Boolean *pPassed, |
| 942 SECErrorCodes *pReturnCode, | 1002 SECErrorCodes *pReturnCode, |
| 943 void *plContext) | 1003 void *plContext) |
| 944 { | 1004 { |
| 945 PRTime time = 0; | 1005 PRTime time = 0; |
| 946 SECStatus rv = SECFailure; | 1006 SECStatus rv = SECFailure; |
| 947 SECStatus rvCache; | 1007 CERTOCSPSingleResponse *single = NULL; |
| 948 PRBool certIDWasConsumed = PR_FALSE; | |
| 949 | 1008 |
| 950 PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_GetStatusForCert"); | 1009 PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_GetStatusForCert"); |
| 951 PKIX_NULLCHECK_THREE(response, pPassed, pReturnCode); | 1010 PKIX_NULLCHECK_THREE(response, pPassed, pReturnCode); |
| 952 | 1011 |
| 953 /* | 1012 /* |
| 954 * It is an error to call this function except following a successful | 1013 * It is an error to call this function except following a successful |
| 955 * return from pkix_pl_OcspResponse_VerifySignature, which would have | 1014 * return from pkix_pl_OcspResponse_VerifySignature, which would have |
| 956 * set response->signerCert. | 1015 * set response->signerCert. |
| 957 */ | 1016 */ |
| 958 PKIX_NULLCHECK_TWO(response->signerCert, response->request); | 1017 PKIX_NULLCHECK_TWO(response->signerCert, response->request); |
| 959 PKIX_NULLCHECK_TWO(cid, cid->certID); | 1018 PKIX_NULLCHECK_TWO(cid, cid->certID); |
| 960 | 1019 |
| 961 if (validity != NULL) { | 1020 if (validity != NULL) { |
| 962 PKIX_Error *er = pkix_pl_Date_GetPRTime(validity, &time, plContext); | 1021 PKIX_Error *er = pkix_pl_Date_GetPRTime(validity, &time, plContext); |
| 963 PKIX_DECREF(er); | 1022 PKIX_DECREF(er); |
| 964 } | 1023 } |
| 965 if (!time) { | 1024 if (!time) { |
| 966 time = PR_Now(); | 1025 time = PR_Now(); |
| 967 } | 1026 } |
| 968 | 1027 |
| 969 rv = cert_ProcessOCSPResponse(response->handle, | 1028 rv = ocsp_GetVerifiedSingleResponseForCertID(response->handle, |
| 970 response->nssOCSPResponse, | 1029 response->nssOCSPResponse, |
| 971 cid->certID, | 1030 cid->certID, |
| 972 response->signerCert, | 1031 response->signerCert, |
| 973 time, | 1032 time, &single); |
| 974 &certIDWasConsumed, | 1033 if (rv == SECSuccess) { |
| 975 &rvCache); | 1034 /* |
| 976 if (certIDWasConsumed) { | 1035 * Check whether the status says revoked, and if so |
| 977 cid->certID = NULL; | 1036 * how that compares to the time value passed into this routine. |
| 1037 */ |
| 1038 rv = ocsp_CertHasGoodStatus(single->certStatus, time); |
| 1039 } |
| 1040 |
| 1041 if (rv == SECSuccess || allowCachingOfFailures) { |
| 1042 /* allowed to update the cache */ |
| 1043 PRBool certIDWasConsumed = PR_FALSE; |
| 1044 |
| 1045 if (single) { |
| 1046 ocsp_CacheSingleResponse(cid->certID,single, |
| 1047 &certIDWasConsumed); |
| 1048 } else { |
| 1049 cert_RememberOCSPProcessingFailure(cid->certID, |
| 1050 &certIDWasConsumed); |
| 1051 } |
| 1052 |
| 1053 if (certIDWasConsumed) { |
| 1054 cid->certID = NULL; |
| 1055 } |
| 978 } | 1056 } |
| 979 | 1057 |
| 980 if (rv == SECSuccess) { | 1058 if (rv == SECSuccess) { |
| 981 *pPassed = PKIX_TRUE; | 1059 *pPassed = PKIX_TRUE; |
| 982 *pReturnCode = 0; | 1060 *pReturnCode = 0; |
| 983 } else { | 1061 } else { |
| 984 *pPassed = PKIX_FALSE; | 1062 *pPassed = PKIX_FALSE; |
| 985 *pReturnCode = PORT_GetError(); | 1063 *pReturnCode = PORT_GetError(); |
| 986 } | 1064 } |
| 987 | 1065 |
| 988 PKIX_RETURN(OCSPRESPONSE); | 1066 PKIX_RETURN(OCSPRESPONSE); |
| 989 } | 1067 } |
| OLD | NEW |