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 |