| 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 /* | 5 /* |
| 6 * Implementation of OCSP services, for both client and server. | 6 * Implementation of OCSP services, for both client and server. |
| 7 * (XXX, really, mostly just for client right now, but intended to do both.) | 7 * (XXX, really, mostly just for client right now, but intended to do both.) |
| 8 */ | 8 */ |
| 9 | 9 |
| 10 #include "prerror.h" | 10 #include "prerror.h" |
| 11 #include "prprf.h" | 11 #include "prprf.h" |
| 12 #include "plarena.h" | 12 #include "plarena.h" |
| 13 #include "prnetdb.h" | 13 #include "prnetdb.h" |
| 14 | 14 |
| 15 #include "seccomon.h" | 15 #include "seccomon.h" |
| 16 #include "secitem.h" | 16 #include "secitem.h" |
| 17 #include "secoidt.h" | 17 #include "secoidt.h" |
| 18 #include "secasn1.h" | 18 #include "secasn1.h" |
| 19 #include "secder.h" | 19 #include "secder.h" |
| 20 #include "cert.h" | 20 #include "cert.h" |
| 21 #include "xconst.h" | 21 #include "xconst.h" |
| 22 #include "secerr.h" | 22 #include "secerr.h" |
| 23 #include "secoid.h" | 23 #include "secoid.h" |
| 24 #include "hasht.h" | 24 #include "hasht.h" |
| 25 #include "sechash.h" | 25 #include "sechash.h" |
| 26 #include "secasn1.h" | 26 #include "secasn1.h" |
| 27 #include "plbase64.h" |
| 27 #include "keyhi.h" | 28 #include "keyhi.h" |
| 28 #include "cryptohi.h" | 29 #include "cryptohi.h" |
| 29 #include "ocsp.h" | 30 #include "ocsp.h" |
| 30 #include "ocspti.h" | 31 #include "ocspti.h" |
| 31 #include "ocspi.h" | 32 #include "ocspi.h" |
| 32 #include "genname.h" | 33 #include "genname.h" |
| 33 #include "certxutl.h" | 34 #include "certxutl.h" |
| 34 #include "pk11func.h" /* for PK11_HashBuf */ | 35 #include "pk11func.h" /* for PK11_HashBuf */ |
| 35 #include <stdarg.h> | 36 #include <stdarg.h> |
| 36 #include <plhash.h> | 37 #include <plhash.h> |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 static struct OCSPGlobalStruct { | 80 static struct OCSPGlobalStruct { |
| 80 PRMonitor *monitor; | 81 PRMonitor *monitor; |
| 81 const SEC_HttpClientFcn *defaultHttpClientFcn; | 82 const SEC_HttpClientFcn *defaultHttpClientFcn; |
| 82 PRInt32 maxCacheEntries; | 83 PRInt32 maxCacheEntries; |
| 83 PRUint32 minimumSecondsToNextFetchAttempt; | 84 PRUint32 minimumSecondsToNextFetchAttempt; |
| 84 PRUint32 maximumSecondsToNextFetchAttempt; | 85 PRUint32 maximumSecondsToNextFetchAttempt; |
| 85 PRUint32 timeoutSeconds; | 86 PRUint32 timeoutSeconds; |
| 86 OCSPCacheData cache; | 87 OCSPCacheData cache; |
| 87 SEC_OcspFailureMode ocspFailureMode; | 88 SEC_OcspFailureMode ocspFailureMode; |
| 88 CERT_StringFromCertFcn alternateOCSPAIAFcn; | 89 CERT_StringFromCertFcn alternateOCSPAIAFcn; |
| 90 PRBool forcePost; |
| 89 } OCSP_Global = { NULL, | 91 } OCSP_Global = { NULL, |
| 90 NULL, | 92 NULL, |
| 91 DEFAULT_OCSP_CACHE_SIZE, | 93 DEFAULT_OCSP_CACHE_SIZE, |
| 92 DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT, | 94 DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT, |
| 93 DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT, | 95 DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT, |
| 94 DEFAULT_OSCP_TIMEOUT_SECONDS, | 96 DEFAULT_OSCP_TIMEOUT_SECONDS, |
| 95 {NULL, 0, NULL, NULL}, | 97 {NULL, 0, NULL, NULL}, |
| 96 ocspMode_FailureIsVerificationFailure, | 98 ocspMode_FailureIsVerificationFailure, |
| 97 NULL | 99 NULL, |
| 100 PR_FALSE |
| 98 }; | 101 }; |
| 99 | 102 |
| 100 | 103 |
| 101 | 104 |
| 102 /* Forward declarations */ | 105 /* Forward declarations */ |
| 103 static SECItem * | 106 static SECItem * |
| 104 ocsp_GetEncodedOCSPResponseFromRequest(PLArenaPool *arena, | 107 ocsp_GetEncodedOCSPResponseFromRequest(PLArenaPool *arena, |
| 105 CERTOCSPRequest *request, | 108 CERTOCSPRequest *request, |
| 106 const char *location, PRTime time, | 109 const char *location, |
| 110 » » » » const char *method, |
| 111 » » » » PRTime time, |
| 107 PRBool addServiceLocator, | 112 PRBool addServiceLocator, |
| 108 void *pwArg, | 113 void *pwArg, |
| 109 CERTOCSPRequest **pRequest); | 114 CERTOCSPRequest **pRequest); |
| 110 static SECStatus | 115 static SECStatus |
| 111 ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle *handle, | 116 ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle *handle, |
| 112 CERTOCSPCertID *certID, | 117 CERTOCSPCertID *certID, |
| 113 CERTCertificate *cert, | 118 CERTCertificate *cert, |
| 114 PRTime time, | 119 PRTime time, |
| 115 void *pwArg, | 120 void *pwArg, |
| 116 PRBool *certIDWasConsumed, | 121 PRBool *certIDWasConsumed, |
| 117 SECStatus *rv_ocsp); | 122 SECStatus *rv_ocsp); |
| 118 | 123 |
| 119 static SECStatus | 124 static SECStatus |
| 120 ocsp_CacheEncodedOCSPResponse(CERTCertDBHandle *handle, | 125 ocsp_GetDecodedVerifiedSingleResponseForID(CERTCertDBHandle *handle, |
| 121 » » » CERTOCSPCertID *certID, | 126 » » » » » CERTOCSPCertID *certID, |
| 122 » » » CERTCertificate *cert, | 127 » » » » » CERTCertificate *cert, |
| 123 » » » PRTime time, | 128 » » » » » PRTime time, |
| 124 » » » void *pwArg, | 129 » » » » » void *pwArg, |
| 125 » » » const SECItem *encodedResponse, | 130 » » » » » const SECItem *encodedResponse, |
| 126 » » » PRBool cacheInvalid, | 131 » » » » » CERTOCSPResponse **pDecodedResponse, |
| 127 » » » PRBool *certIDWasConsumed, | 132 » » » » » CERTOCSPSingleResponse **pSingle); |
| 128 » » » SECStatus *rv_ocsp); | |
| 129 | |
| 130 static SECStatus | |
| 131 ocsp_GetVerifiedSingleResponseForCertID(CERTCertDBHandle *handle, | |
| 132 CERTOCSPResponse *response, | |
| 133 CERTOCSPCertID *certID, | |
| 134 CERTCertificate *signerCert, | |
| 135 PRTime time, | |
| 136 CERTOCSPSingleResponse **pSingleResponse
); | |
| 137 | 133 |
| 138 static SECStatus | 134 static SECStatus |
| 139 ocsp_CertRevokedAfter(ocspRevokedInfo *revokedInfo, PRTime time); | 135 ocsp_CertRevokedAfter(ocspRevokedInfo *revokedInfo, PRTime time); |
| 140 | 136 |
| 141 static CERTOCSPCertID * | 137 static CERTOCSPCertID * |
| 142 cert_DupOCSPCertID(const CERTOCSPCertID *src); | 138 cert_DupOCSPCertID(const CERTOCSPCertID *src); |
| 143 | 139 |
| 144 #ifndef DEBUG | 140 #ifndef DEBUG |
| 145 #define OCSP_TRACE(msg) | 141 #define OCSP_TRACE(msg) |
| 146 #define OCSP_TRACE_TIME(msg, time) | 142 #define OCSP_TRACE_TIME(msg, time) |
| (...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 747 OCSP_TRACE_TIME("nextFetchAttemptTime", | 743 OCSP_TRACE_TIME("nextFetchAttemptTime", |
| 748 latestTimeWhenResponseIsConsideredFresh); | 744 latestTimeWhenResponseIsConsideredFresh); |
| 749 | 745 |
| 750 PR_ExitMonitor(OCSP_Global.monitor); | 746 PR_ExitMonitor(OCSP_Global.monitor); |
| 751 } | 747 } |
| 752 | 748 |
| 753 static PRBool | 749 static PRBool |
| 754 ocsp_IsCacheItemFresh(OCSPCacheItem *cacheItem) | 750 ocsp_IsCacheItemFresh(OCSPCacheItem *cacheItem) |
| 755 { | 751 { |
| 756 PRTime now; | 752 PRTime now; |
| 757 PRBool retval; | 753 PRBool fresh; |
| 758 | 754 |
| 759 PR_EnterMonitor(OCSP_Global.monitor); | |
| 760 now = PR_Now(); | 755 now = PR_Now(); |
| 761 retval = (cacheItem->nextFetchAttemptTime > now); | 756 |
| 762 OCSP_TRACE(("OCSP ocsp_IsCacheItemFresh: %d\n", retval)); | 757 fresh = cacheItem->nextFetchAttemptTime > now; |
| 763 PR_ExitMonitor(OCSP_Global.monitor); | 758 |
| 764 return retval; | 759 /* Work around broken OCSP responders that return unknown responses for |
| 760 * certificates, especially certificates that were just recently issued. |
| 761 */ |
| 762 if (fresh && cacheItem->certStatusArena && |
| 763 cacheItem->certStatus.certStatusType == ocspCertStatus_unknown) { |
| 764 fresh = PR_FALSE; |
| 765 } |
| 766 |
| 767 OCSP_TRACE(("OCSP ocsp_IsCacheItemFresh: %d\n", fresh)); |
| 768 |
| 769 return fresh; |
| 765 } | 770 } |
| 766 | 771 |
| 767 /* | 772 /* |
| 768 * Status in *certIDWasConsumed will always be correct, regardless of | 773 * Status in *certIDWasConsumed will always be correct, regardless of |
| 769 * return value. | 774 * return value. |
| 770 * If the caller is unable to transfer ownership of certID, | 775 * If the caller is unable to transfer ownership of certID, |
| 771 * then the caller must set certIDWasConsumed to NULL, | 776 * then the caller must set certIDWasConsumed to NULL, |
| 772 * and this function will potentially duplicate the certID object. | 777 * and this function will potentially duplicate the certID object. |
| 773 */ | 778 */ |
| 774 static SECStatus | 779 static SECStatus |
| 775 ocsp_CreateOrUpdateCacheEntry(OCSPCacheData *cache, | 780 ocsp_CreateOrUpdateCacheEntry(OCSPCacheData *cache, |
| 776 CERTOCSPCertID *certID, | 781 CERTOCSPCertID *certID, |
| 777 CERTOCSPSingleResponse *single, | 782 CERTOCSPSingleResponse *single, |
| 778 PRBool *certIDWasConsumed) | 783 PRBool *certIDWasConsumed) |
| 779 { | 784 { |
| 780 SECStatus rv; | 785 SECStatus rv; |
| 781 OCSPCacheItem *cacheItem; | 786 OCSPCacheItem *cacheItem; |
| 782 OCSP_TRACE(("OCSP ocsp_CreateOrUpdateCacheEntry\n")); | 787 OCSP_TRACE(("OCSP ocsp_CreateOrUpdateCacheEntry\n")); |
| 783 | 788 |
| 784 if (certIDWasConsumed) | 789 if (certIDWasConsumed) |
| 785 *certIDWasConsumed = PR_FALSE; | 790 *certIDWasConsumed = PR_FALSE; |
| 786 | 791 |
| 787 PR_EnterMonitor(OCSP_Global.monitor); | 792 PR_EnterMonitor(OCSP_Global.monitor); |
| 788 PORT_Assert(OCSP_Global.maxCacheEntries >= 0); | 793 PORT_Assert(OCSP_Global.maxCacheEntries >= 0); |
| 789 | 794 |
| 790 cacheItem = ocsp_FindCacheEntry(cache, certID); | 795 cacheItem = ocsp_FindCacheEntry(cache, certID); |
| 796 |
| 797 /* Don't replace an unknown or revoked entry with an error entry, even if |
| 798 * the existing entry is expired. Instead, we'll continue to use the |
| 799 * existing (possibly expired) cache entry until we receive a valid signed |
| 800 * response to replace it. |
| 801 */ |
| 802 if (!single && cacheItem && cacheItem->certStatusArena && |
| 803 (cacheItem->certStatus.certStatusType == ocspCertStatus_revoked || |
| 804 cacheItem->certStatus.certStatusType == ocspCertStatus_unknown)) { |
| 805 PR_ExitMonitor(OCSP_Global.monitor); |
| 806 return SECSuccess; |
| 807 } |
| 808 |
| 791 if (!cacheItem) { | 809 if (!cacheItem) { |
| 792 CERTOCSPCertID *myCertID; | 810 CERTOCSPCertID *myCertID; |
| 793 if (certIDWasConsumed) { | 811 if (certIDWasConsumed) { |
| 794 myCertID = certID; | 812 myCertID = certID; |
| 795 *certIDWasConsumed = PR_TRUE; | 813 *certIDWasConsumed = PR_TRUE; |
| 796 } else { | 814 } else { |
| 797 myCertID = cert_DupOCSPCertID(certID); | 815 myCertID = cert_DupOCSPCertID(certID); |
| 798 if (!myCertID) { | 816 if (!myCertID) { |
| 799 PR_ExitMonitor(OCSP_Global.monitor); | 817 PR_ExitMonitor(OCSP_Global.monitor); |
| 800 PORT_SetError(PR_OUT_OF_MEMORY_ERROR); | 818 PORT_SetError(PR_OUT_OF_MEMORY_ERROR); |
| (...skipping 652 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1453 * not needed if not signing.) | 1471 * not needed if not signing.) |
| 1454 * RETURN: | 1472 * RETURN: |
| 1455 * Returns a NULL on error and a pointer to the SECItem with the | 1473 * Returns a NULL on error and a pointer to the SECItem with the |
| 1456 * encoded value otherwise. Any error is likely to be low-level | 1474 * encoded value otherwise. Any error is likely to be low-level |
| 1457 * (e.g. no memory). | 1475 * (e.g. no memory). |
| 1458 */ | 1476 */ |
| 1459 SECItem * | 1477 SECItem * |
| 1460 CERT_EncodeOCSPRequest(PLArenaPool *arena, CERTOCSPRequest *request, | 1478 CERT_EncodeOCSPRequest(PLArenaPool *arena, CERTOCSPRequest *request, |
| 1461 void *pwArg) | 1479 void *pwArg) |
| 1462 { | 1480 { |
| 1463 ocspTBSRequest *tbsRequest; | |
| 1464 SECStatus rv; | 1481 SECStatus rv; |
| 1465 | 1482 |
| 1466 /* XXX All of these should generate errors if they fail. */ | 1483 /* XXX All of these should generate errors if they fail. */ |
| 1467 PORT_Assert(request); | 1484 PORT_Assert(request); |
| 1468 PORT_Assert(request->tbsRequest); | 1485 PORT_Assert(request->tbsRequest); |
| 1469 | 1486 |
| 1470 tbsRequest = request->tbsRequest; | |
| 1471 | |
| 1472 if (request->tbsRequest->extensionHandle != NULL) { | 1487 if (request->tbsRequest->extensionHandle != NULL) { |
| 1473 rv = CERT_FinishExtensions(request->tbsRequest->extensionHandle); | 1488 rv = CERT_FinishExtensions(request->tbsRequest->extensionHandle); |
| 1474 request->tbsRequest->extensionHandle = NULL; | 1489 request->tbsRequest->extensionHandle = NULL; |
| 1475 if (rv != SECSuccess) | 1490 if (rv != SECSuccess) |
| 1476 return NULL; | 1491 return NULL; |
| 1477 } | 1492 } |
| 1478 | 1493 |
| 1479 /* | 1494 /* |
| 1480 * XXX When signed requests are supported and request->optionalSignature | 1495 * XXX When signed requests are supported and request->optionalSignature |
| 1481 * is not NULL: | 1496 * is not NULL: |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1629 } | 1644 } |
| 1630 | 1645 |
| 1631 /* | 1646 /* |
| 1632 * Digest the cert's subject public key using the specified algorithm. | 1647 * Digest the cert's subject public key using the specified algorithm. |
| 1633 * The necessary storage for the digest data is allocated. If "fill" is | 1648 * The necessary storage for the digest data is allocated. If "fill" is |
| 1634 * non-null, the data is put there, otherwise a SECItem is allocated. | 1649 * non-null, the data is put there, otherwise a SECItem is allocated. |
| 1635 * Allocation from "arena" if it is non-null, heap otherwise. Any problem | 1650 * Allocation from "arena" if it is non-null, heap otherwise. Any problem |
| 1636 * results in a NULL being returned (and an appropriate error set). | 1651 * results in a NULL being returned (and an appropriate error set). |
| 1637 */ | 1652 */ |
| 1638 SECItem * | 1653 SECItem * |
| 1639 CERT_GetSPKIDigest(PLArenaPool *arena, const CERTCertificate *cert, | 1654 CERT_GetSubjectPublicKeyDigest(PLArenaPool *arena, const CERTCertificate *cert, |
| 1640 SECOidTag digestAlg, SECItem *fill) | 1655 SECOidTag digestAlg, SECItem *fill) |
| 1641 { | 1656 { |
| 1642 SECItem spk; | 1657 SECItem spk; |
| 1643 | 1658 |
| 1644 /* | 1659 /* |
| 1645 * Copy just the length and data pointer (nothing needs to be freed) | 1660 * Copy just the length and data pointer (nothing needs to be freed) |
| 1646 * of the subject public key so we can convert the length from bits | 1661 * of the subject public key so we can convert the length from bits |
| 1647 * to bytes, which is what the digest function expects. | 1662 * to bytes, which is what the digest function expects. |
| 1648 */ | 1663 */ |
| 1649 spk = cert->subjectPublicKeyInfo.subjectPublicKey; | 1664 spk = cert->subjectPublicKeyInfo.subjectPublicKey; |
| 1650 DER_ConvertBitString(&spk); | 1665 DER_ConvertBitString(&spk); |
| 1651 | 1666 |
| 1652 return ocsp_DigestValue(arena, digestAlg, fill, &spk); | 1667 return ocsp_DigestValue(arena, digestAlg, fill, &spk); |
| 1653 } | 1668 } |
| 1654 | 1669 |
| 1655 /* | 1670 /* |
| 1656 * Digest the cert's subject name using the specified algorithm. | 1671 * Digest the cert's subject name using the specified algorithm. |
| 1657 */ | 1672 */ |
| 1658 static SECItem * | 1673 SECItem * |
| 1659 cert_GetSubjectNameDigest(PLArenaPool *arena, const CERTCertificate *cert, | 1674 CERT_GetSubjectNameDigest(PLArenaPool *arena, const CERTCertificate *cert, |
| 1660 SECOidTag digestAlg, SECItem *fill) | 1675 SECOidTag digestAlg, SECItem *fill) |
| 1661 { | 1676 { |
| 1662 SECItem name; | 1677 SECItem name; |
| 1663 | 1678 |
| 1664 /* | 1679 /* |
| 1665 * Copy just the length and data pointer (nothing needs to be freed) | 1680 * Copy just the length and data pointer (nothing needs to be freed) |
| 1666 * of the subject name | 1681 * of the subject name |
| 1667 */ | 1682 */ |
| 1668 name = cert->derSubject; | 1683 name = cert->derSubject; |
| 1669 | 1684 |
| 1670 return ocsp_DigestValue(arena, digestAlg, fill, &name); | 1685 return ocsp_DigestValue(arena, digestAlg, fill, &name); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1699 NULL); | 1714 NULL); |
| 1700 if (rv != SECSuccess) { | 1715 if (rv != SECSuccess) { |
| 1701 goto loser; | 1716 goto loser; |
| 1702 } | 1717 } |
| 1703 | 1718 |
| 1704 issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA); | 1719 issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA); |
| 1705 if (issuerCert == NULL) { | 1720 if (issuerCert == NULL) { |
| 1706 goto loser; | 1721 goto loser; |
| 1707 } | 1722 } |
| 1708 | 1723 |
| 1709 if (cert_GetSubjectNameDigest(arena, issuerCert, SEC_OID_SHA1, | 1724 if (CERT_GetSubjectNameDigest(arena, issuerCert, SEC_OID_SHA1, |
| 1710 &(certID->issuerNameHash)) == NULL) { | 1725 &(certID->issuerNameHash)) == NULL) { |
| 1711 goto loser; | 1726 goto loser; |
| 1712 } | 1727 } |
| 1713 certID->issuerSHA1NameHash.data = certID->issuerNameHash.data; | 1728 certID->issuerSHA1NameHash.data = certID->issuerNameHash.data; |
| 1714 certID->issuerSHA1NameHash.len = certID->issuerNameHash.len; | 1729 certID->issuerSHA1NameHash.len = certID->issuerNameHash.len; |
| 1715 | 1730 |
| 1716 if (cert_GetSubjectNameDigest(arena, issuerCert, SEC_OID_MD5, | 1731 if (CERT_GetSubjectNameDigest(arena, issuerCert, SEC_OID_MD5, |
| 1717 &(certID->issuerMD5NameHash)) == NULL) { | 1732 &(certID->issuerMD5NameHash)) == NULL) { |
| 1718 goto loser; | 1733 goto loser; |
| 1719 } | 1734 } |
| 1720 | 1735 |
| 1721 if (cert_GetSubjectNameDigest(arena, issuerCert, SEC_OID_MD2, | 1736 if (CERT_GetSubjectNameDigest(arena, issuerCert, SEC_OID_MD2, |
| 1722 &(certID->issuerMD2NameHash)) == NULL) { | 1737 &(certID->issuerMD2NameHash)) == NULL) { |
| 1723 goto loser; | 1738 goto loser; |
| 1724 } | 1739 } |
| 1725 | 1740 |
| 1726 if (CERT_GetSPKIDigest(arena, issuerCert, SEC_OID_SHA1, | 1741 if (CERT_GetSubjectPublicKeyDigest(arena, issuerCert, SEC_OID_SHA1, |
| 1727 » » » » &(certID->issuerKeyHash)) == NULL) { | 1742 » » » » &certID->issuerKeyHash) == NULL) { |
| 1728 goto loser; | 1743 goto loser; |
| 1729 } | 1744 } |
| 1730 certID->issuerSHA1KeyHash.data = certID->issuerKeyHash.data; | 1745 certID->issuerSHA1KeyHash.data = certID->issuerKeyHash.data; |
| 1731 certID->issuerSHA1KeyHash.len = certID->issuerKeyHash.len; | 1746 certID->issuerSHA1KeyHash.len = certID->issuerKeyHash.len; |
| 1732 /* cache the other two hash algorithms as well */ | 1747 /* cache the other two hash algorithms as well */ |
| 1733 if (CERT_GetSPKIDigest(arena, issuerCert, SEC_OID_MD5, | 1748 if (CERT_GetSubjectPublicKeyDigest(arena, issuerCert, SEC_OID_MD5, |
| 1734 » » » » &(certID->issuerMD5KeyHash)) == NULL) { | 1749 » » » » &certID->issuerMD5KeyHash) == NULL) { |
| 1735 goto loser; | 1750 goto loser; |
| 1736 } | 1751 } |
| 1737 if (CERT_GetSPKIDigest(arena, issuerCert, SEC_OID_MD2, | 1752 if (CERT_GetSubjectPublicKeyDigest(arena, issuerCert, SEC_OID_MD2, |
| 1738 » » » » &(certID->issuerMD2KeyHash)) == NULL) { | 1753 » » » » &certID->issuerMD2KeyHash) == NULL) { |
| 1739 goto loser; | 1754 goto loser; |
| 1740 } | 1755 } |
| 1741 | 1756 |
| 1742 | 1757 |
| 1743 /* now we are done with issuerCert */ | 1758 /* now we are done with issuerCert */ |
| 1744 CERT_DestroyCertificate(issuerCert); | 1759 CERT_DestroyCertificate(issuerCert); |
| 1745 issuerCert = NULL; | 1760 issuerCert = NULL; |
| 1746 | 1761 |
| 1747 rv = SECITEM_CopyItem(arena, &certID->serialNumber, &cert->serialNumber); | 1762 rv = SECITEM_CopyItem(arena, &certID->serialNumber, &cert->serialNumber); |
| 1748 if (rv != SECSuccess) { | 1763 if (rv != SECSuccess) { |
| (...skipping 1224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2973 return NULL; | 2988 return NULL; |
| 2974 } | 2989 } |
| 2975 | 2990 |
| 2976 /* | 2991 /* |
| 2977 * Sends an encoded OCSP request to the server identified by "location", | 2992 * Sends an encoded OCSP request to the server identified by "location", |
| 2978 * and returns the socket on which it was sent (so can listen for the reply). | 2993 * and returns the socket on which it was sent (so can listen for the reply). |
| 2979 * "location" is expected to be a valid URL -- an error parsing it produces | 2994 * "location" is expected to be a valid URL -- an error parsing it produces |
| 2980 * SEC_ERROR_CERT_BAD_ACCESS_LOCATION. Other errors are likely problems | 2995 * SEC_ERROR_CERT_BAD_ACCESS_LOCATION. Other errors are likely problems |
| 2981 * connecting to it, or writing to it, or allocating memory, and the low-level | 2996 * connecting to it, or writing to it, or allocating memory, and the low-level |
| 2982 * errors appropriate to the problem will be set. | 2997 * errors appropriate to the problem will be set. |
| 2998 * if (encodedRequest == NULL) |
| 2999 * then location MUST already include the full request, |
| 3000 * including base64 and urlencode, |
| 3001 * and the request will be sent with GET |
| 3002 * if (encodedRequest != NULL) |
| 3003 * then the request will be sent with POST |
| 2983 */ | 3004 */ |
| 2984 static PRFileDesc * | 3005 static PRFileDesc * |
| 2985 ocsp_SendEncodedRequest(const char *location, const SECItem *encodedRequest) | 3006 ocsp_SendEncodedRequest(const char *location, const SECItem *encodedRequest) |
| 2986 { | 3007 { |
| 2987 char *hostname = NULL; | 3008 char *hostname = NULL; |
| 2988 char *path = NULL; | 3009 char *path = NULL; |
| 2989 PRUint16 port; | 3010 PRUint16 port; |
| 2990 SECStatus rv; | 3011 SECStatus rv; |
| 2991 PRFileDesc *sock = NULL; | 3012 PRFileDesc *sock = NULL; |
| 2992 PRFileDesc *returnSock = NULL; | 3013 PRFileDesc *returnSock = NULL; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3005 | 3026 |
| 3006 sock = ocsp_ConnectToHost(hostname, port); | 3027 sock = ocsp_ConnectToHost(hostname, port); |
| 3007 if (sock == NULL) | 3028 if (sock == NULL) |
| 3008 goto loser; | 3029 goto loser; |
| 3009 | 3030 |
| 3010 portstr[0] = '\0'; | 3031 portstr[0] = '\0'; |
| 3011 if (port != 80) { | 3032 if (port != 80) { |
| 3012 PR_snprintf(portstr, sizeof(portstr), ":%d", port); | 3033 PR_snprintf(portstr, sizeof(portstr), ":%d", port); |
| 3013 } | 3034 } |
| 3014 | 3035 |
| 3015 header = PR_smprintf("POST %s HTTP/1.0\r\n" | 3036 if (!encodedRequest) { |
| 3016 » » » "Host: %s%s\r\n" | 3037 header = PR_smprintf("GET %s HTTP/1.0\r\n" |
| 3017 » » » "Content-Type: application/ocsp-request\r\n" | 3038 "Host: %s%s\r\n\r\n", |
| 3018 » » » "Content-Length: %u\r\n\r\n", | 3039 path, hostname, portstr); |
| 3019 » » » path, hostname, portstr, encodedRequest->len); | 3040 if (header == NULL) |
| 3020 if (header == NULL) | 3041 goto loser; |
| 3021 » goto loser; | |
| 3022 | 3042 |
| 3023 /* | 3043 /* |
| 3024 * The NSPR documentation promises that if it can, it will write the full | 3044 * The NSPR documentation promises that if it can, it will write the full |
| 3025 * amount; this will not return a partial value expecting us to loop. | 3045 * amount; this will not return a partial value expecting us to loop. |
| 3026 */ | 3046 */ |
| 3027 if (PR_Write(sock, header, (PRInt32) PORT_Strlen(header)) < 0) | 3047 if (PR_Write(sock, header, (PRInt32) PORT_Strlen(header)) < 0) |
| 3028 » goto loser; | 3048 goto loser; |
| 3049 } |
| 3050 else { |
| 3051 header = PR_smprintf("POST %s HTTP/1.0\r\n" |
| 3052 "Host: %s%s\r\n" |
| 3053 "Content-Type: application/ocsp-request\r\n" |
| 3054 "Content-Length: %u\r\n\r\n", |
| 3055 path, hostname, portstr, encodedRequest->len); |
| 3056 if (header == NULL) |
| 3057 goto loser; |
| 3029 | 3058 |
| 3030 if (PR_Write(sock, encodedRequest->data, | 3059 /* |
| 3031 » » (PRInt32) encodedRequest->len) < 0) | 3060 * The NSPR documentation promises that if it can, it will write the full |
| 3032 » goto loser; | 3061 * amount; this will not return a partial value expecting us to loop. |
| 3062 */ |
| 3063 if (PR_Write(sock, header, (PRInt32) PORT_Strlen(header)) < 0) |
| 3064 goto loser; |
| 3065 |
| 3066 if (PR_Write(sock, encodedRequest->data, |
| 3067 (PRInt32) encodedRequest->len) < 0) |
| 3068 goto loser; |
| 3069 } |
| 3033 | 3070 |
| 3034 returnSock = sock; | 3071 returnSock = sock; |
| 3035 sock = NULL; | 3072 sock = NULL; |
| 3036 | 3073 |
| 3037 loser: | 3074 loser: |
| 3038 if (header != NULL) | 3075 if (header != NULL) |
| 3039 PORT_Free(header); | 3076 PORT_Free(header); |
| 3040 if (sock != NULL) | 3077 if (sock != NULL) |
| 3041 PR_Close(sock); | 3078 PR_Close(sock); |
| 3042 if (path != NULL) | 3079 if (path != NULL) |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3331 CERT_ParseURL(const char *url, char **pHostname, PRUint16 *pPort, char **pPath) | 3368 CERT_ParseURL(const char *url, char **pHostname, PRUint16 *pPort, char **pPath) |
| 3332 { | 3369 { |
| 3333 return ocsp_ParseURL(url, pHostname, pPort, pPath); | 3370 return ocsp_ParseURL(url, pHostname, pPort, pPath); |
| 3334 } | 3371 } |
| 3335 | 3372 |
| 3336 /* | 3373 /* |
| 3337 * Limit the size of http responses we are willing to accept. | 3374 * Limit the size of http responses we are willing to accept. |
| 3338 */ | 3375 */ |
| 3339 #define MAX_WANTED_OCSP_RESPONSE_LEN 64*1024 | 3376 #define MAX_WANTED_OCSP_RESPONSE_LEN 64*1024 |
| 3340 | 3377 |
| 3378 /* if (encodedRequest == NULL) |
| 3379 * then location MUST already include the full request, |
| 3380 * including base64 and urlencode, |
| 3381 * and the request will be sent with GET |
| 3382 * if (encodedRequest != NULL) |
| 3383 * then the request will be sent with POST |
| 3384 */ |
| 3341 static SECItem * | 3385 static SECItem * |
| 3342 fetchOcspHttpClientV1(PLArenaPool *arena, | 3386 fetchOcspHttpClientV1(PLArenaPool *arena, |
| 3343 const SEC_HttpClientFcnV1 *hcv1, | 3387 const SEC_HttpClientFcnV1 *hcv1, |
| 3344 const char *location, | 3388 const char *location, |
| 3345 const SECItem *encodedRequest) | 3389 const SECItem *encodedRequest) |
| 3346 { | 3390 { |
| 3347 char *hostname = NULL; | 3391 char *hostname = NULL; |
| 3348 char *path = NULL; | 3392 char *path = NULL; |
| 3349 PRUint16 port; | 3393 PRUint16 port; |
| 3350 SECItem *encodedResponse = NULL; | 3394 SECItem *encodedResponse = NULL; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 3374 - the client will use blocking I/O | 3418 - the client will use blocking I/O |
| 3375 - TryFcn will not return WOULD_BLOCK nor a poll descriptor | 3419 - TryFcn will not return WOULD_BLOCK nor a poll descriptor |
| 3376 - it's sufficient to call TryFcn once | 3420 - it's sufficient to call TryFcn once |
| 3377 No lock for accessing OCSP_Global.timeoutSeconds, bug 406120 | 3421 No lock for accessing OCSP_Global.timeoutSeconds, bug 406120 |
| 3378 */ | 3422 */ |
| 3379 | 3423 |
| 3380 if ((*hcv1->createFcn)( | 3424 if ((*hcv1->createFcn)( |
| 3381 pServerSession, | 3425 pServerSession, |
| 3382 "http", | 3426 "http", |
| 3383 path, | 3427 path, |
| 3384 "POST", | 3428 encodedRequest ? "POST" : "GET", |
| 3385 PR_TicksPerSecond() * OCSP_Global.timeoutSeconds, | 3429 PR_TicksPerSecond() * OCSP_Global.timeoutSeconds, |
| 3386 &pRequestSession) != SECSuccess) { | 3430 &pRequestSession) != SECSuccess) { |
| 3387 PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR); | 3431 PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR); |
| 3388 goto loser; | 3432 goto loser; |
| 3389 } | 3433 } |
| 3390 | 3434 |
| 3391 if ((*hcv1->setPostDataFcn)( | 3435 if (encodedRequest && |
| 3436 (*hcv1->setPostDataFcn)( |
| 3392 pRequestSession, | 3437 pRequestSession, |
| 3393 (char*)encodedRequest->data, | 3438 (char*)encodedRequest->data, |
| 3394 encodedRequest->len, | 3439 encodedRequest->len, |
| 3395 "application/ocsp-request") != SECSuccess) { | 3440 "application/ocsp-request") != SECSuccess) { |
| 3396 PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR); | 3441 PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR); |
| 3397 goto loser; | 3442 goto loser; |
| 3398 } | 3443 } |
| 3399 | 3444 |
| 3400 /* we don't want result objects larger than this: */ | 3445 /* we don't want result objects larger than this: */ |
| 3401 myHttpResponseDataLen = MAX_WANTED_OCSP_RESPONSE_LEN; | 3446 myHttpResponseDataLen = MAX_WANTED_OCSP_RESPONSE_LEN; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3437 (*hcv1->freeSessionFcn)(pServerSession); | 3482 (*hcv1->freeSessionFcn)(pServerSession); |
| 3438 if (path != NULL) | 3483 if (path != NULL) |
| 3439 PORT_Free(path); | 3484 PORT_Free(path); |
| 3440 if (hostname != NULL) | 3485 if (hostname != NULL) |
| 3441 PORT_Free(hostname); | 3486 PORT_Free(hostname); |
| 3442 | 3487 |
| 3443 return encodedResponse; | 3488 return encodedResponse; |
| 3444 } | 3489 } |
| 3445 | 3490 |
| 3446 /* | 3491 /* |
| 3447 * FUNCTION: CERT_GetEncodedOCSPResponse | 3492 * FUNCTION: CERT_GetEncodedOCSPResponseByMethod |
| 3448 * Creates and sends a request to an OCSP responder, then reads and | 3493 * Creates and sends a request to an OCSP responder, then reads and |
| 3449 * returns the (encoded) response. | 3494 * returns the (encoded) response. |
| 3450 * INPUTS: | 3495 * INPUTS: |
| 3451 * PLArenaPool *arena | 3496 * PLArenaPool *arena |
| 3452 * Pointer to arena from which return value will be allocated. | 3497 * Pointer to arena from which return value will be allocated. |
| 3453 * If NULL, result will be allocated from the heap (and thus should | 3498 * If NULL, result will be allocated from the heap (and thus should |
| 3454 * be freed via SECITEM_FreeItem). | 3499 * be freed via SECITEM_FreeItem). |
| 3455 * CERTCertList *certList | 3500 * CERTCertList *certList |
| 3456 * A list of certs for which status will be requested. | 3501 * A list of certs for which status will be requested. |
| 3457 * Note that all of these certificates should have the same issuer, | 3502 * Note that all of these certificates should have the same issuer, |
| 3458 * or it's expected the response will be signed by a trusted responder. | 3503 * or it's expected the response will be signed by a trusted responder. |
| 3459 * If the certs need to be broken up into multiple requests, that | 3504 * If the certs need to be broken up into multiple requests, that |
| 3460 * must be handled by the caller (and thus by having multiple calls | 3505 * must be handled by the caller (and thus by having multiple calls |
| 3461 * to this routine), who knows about where the request(s) are being | 3506 * to this routine), who knows about where the request(s) are being |
| 3462 * sent and whether there are any trusted responders in place. | 3507 * sent and whether there are any trusted responders in place. |
| 3463 * const char *location | 3508 * const char *location |
| 3464 * The location of the OCSP responder (a URL). | 3509 * The location of the OCSP responder (a URL). |
| 3510 * const char *method |
| 3511 * The protocol method used when retrieving the OCSP response. |
| 3512 * Currently support: "GET" (http GET) and "POST" (http POST). |
| 3513 * Additionals methods for http or other protocols might be added |
| 3514 * in the future. |
| 3465 * PRTime time | 3515 * PRTime time |
| 3466 * Indicates the time for which the certificate status is to be | 3516 * Indicates the time for which the certificate status is to be |
| 3467 * determined -- this may be used in the search for the cert's issuer | 3517 * determined -- this may be used in the search for the cert's issuer |
| 3468 * but has no other bearing on the operation. | 3518 * but has no other bearing on the operation. |
| 3469 * PRBool addServiceLocator | 3519 * PRBool addServiceLocator |
| 3470 * If true, the Service Locator extension should be added to the | 3520 * If true, the Service Locator extension should be added to the |
| 3471 * single request(s) for each cert. | 3521 * single request(s) for each cert. |
| 3472 * CERTCertificate *signerCert | 3522 * CERTCertificate *signerCert |
| 3473 * If non-NULL, means sign the request using this cert. Otherwise, | 3523 * If non-NULL, means sign the request using this cert. Otherwise, |
| 3474 * do not sign. | 3524 * do not sign. |
| 3475 * void *pwArg | 3525 * void *pwArg |
| 3476 * Pointer to argument for password prompting, if needed. (Definitely | 3526 * Pointer to argument for password prompting, if needed. (Definitely |
| 3477 * not needed if not signing.) | 3527 * not needed if not signing.) |
| 3478 * OUTPUTS: | 3528 * OUTPUTS: |
| 3479 * CERTOCSPRequest **pRequest | 3529 * CERTOCSPRequest **pRequest |
| 3480 * Pointer in which to store the OCSP request created for the given | 3530 * Pointer in which to store the OCSP request created for the given |
| 3481 * list of certificates. It is only filled in if the entire operation | 3531 * list of certificates. It is only filled in if the entire operation |
| 3482 * is successful and the pointer is not null -- and in that case the | 3532 * is successful and the pointer is not null -- and in that case the |
| 3483 * caller is then reponsible for destroying it. | 3533 * caller is then reponsible for destroying it. |
| 3484 * RETURN: | 3534 * RETURN: |
| 3485 * Returns a pointer to the SECItem holding the response. | 3535 * Returns a pointer to the SECItem holding the response. |
| 3486 * On error, returns null with error set describing the reason: | 3536 * On error, returns null with error set describing the reason: |
| 3487 * SEC_ERROR_UNKNOWN_ISSUER | 3537 * SEC_ERROR_UNKNOWN_ISSUER |
| 3488 * SEC_ERROR_CERT_BAD_ACCESS_LOCATION | 3538 * SEC_ERROR_CERT_BAD_ACCESS_LOCATION |
| 3489 * SEC_ERROR_OCSP_BAD_HTTP_RESPONSE | 3539 * SEC_ERROR_OCSP_BAD_HTTP_RESPONSE |
| 3490 * Other errors are low-level problems (no memory, bad database, etc.). | 3540 * Other errors are low-level problems (no memory, bad database, etc.). |
| 3491 */ | 3541 */ |
| 3492 SECItem * | 3542 SECItem * |
| 3543 CERT_GetEncodedOCSPResponseByMethod(PLArenaPool *arena, CERTCertList *certList, |
| 3544 const char *location, const char *method, |
| 3545 PRTime time, PRBool addServiceLocator, |
| 3546 CERTCertificate *signerCert, void *pwArg, |
| 3547 CERTOCSPRequest **pRequest) |
| 3548 { |
| 3549 CERTOCSPRequest *request; |
| 3550 request = CERT_CreateOCSPRequest(certList, time, addServiceLocator, |
| 3551 signerCert); |
| 3552 if (!request) |
| 3553 return NULL; |
| 3554 return ocsp_GetEncodedOCSPResponseFromRequest(arena, request, location, |
| 3555 method, time, addServiceLocato
r, |
| 3556 pwArg, pRequest); |
| 3557 } |
| 3558 |
| 3559 /* |
| 3560 * FUNCTION: CERT_GetEncodedOCSPResponse |
| 3561 * Creates and sends a request to an OCSP responder, then reads and |
| 3562 * returns the (encoded) response. |
| 3563 * |
| 3564 * This is a legacy API that behaves identically to |
| 3565 * CERT_GetEncodedOCSPResponseByMethod using the "POST" method. |
| 3566 */ |
| 3567 SECItem * |
| 3493 CERT_GetEncodedOCSPResponse(PLArenaPool *arena, CERTCertList *certList, | 3568 CERT_GetEncodedOCSPResponse(PLArenaPool *arena, CERTCertList *certList, |
| 3494 const char *location, PRTime time, | 3569 const char *location, PRTime time, |
| 3495 PRBool addServiceLocator, | 3570 PRBool addServiceLocator, |
| 3496 CERTCertificate *signerCert, void *pwArg, | 3571 CERTCertificate *signerCert, void *pwArg, |
| 3497 CERTOCSPRequest **pRequest) | 3572 CERTOCSPRequest **pRequest) |
| 3498 { | 3573 { |
| 3499 CERTOCSPRequest *request; | 3574 return CERT_GetEncodedOCSPResponseByMethod(arena, certList, location, |
| 3500 request = CERT_CreateOCSPRequest(certList, time, addServiceLocator, | 3575 » » » » » "POST", time, addServiceLocator, |
| 3501 signerCert); | 3576 » » » » » signerCert, pwArg, pRequest); |
| 3502 if (!request) | |
| 3503 return NULL; | |
| 3504 return ocsp_GetEncodedOCSPResponseFromRequest(arena, request, location, | |
| 3505 time, addServiceLocator, | |
| 3506 pwArg, pRequest); | |
| 3507 } | 3577 } |
| 3508 | 3578 |
| 3579 /* URL encode a buffer that consists of base64-characters, only, |
| 3580 * which means we can use a simple encoding logic. |
| 3581 * |
| 3582 * No output buffer size checking is performed. |
| 3583 * You should call the function twice, to calculate the required buffer size. |
| 3584 * |
| 3585 * If the outpufBuf parameter is NULL, the function will calculate the |
| 3586 * required size, including the trailing zero termination char. |
| 3587 * |
| 3588 * The function returns the number of bytes calculated or produced. |
| 3589 */ |
| 3590 size_t |
| 3591 ocsp_UrlEncodeBase64Buf(const char *base64Buf, char *outputBuf) |
| 3592 { |
| 3593 const char *walkInput = NULL; |
| 3594 char *walkOutput = outputBuf; |
| 3595 size_t count = 0; |
| 3596 |
| 3597 for (walkInput=base64Buf; *walkInput; ++walkInput) { |
| 3598 char c = *walkInput; |
| 3599 if (isspace(c)) |
| 3600 continue; |
| 3601 switch (c) { |
| 3602 case '+': |
| 3603 if (outputBuf) { |
| 3604 strcpy(walkOutput, "%2B"); |
| 3605 walkOutput += 3; |
| 3606 } |
| 3607 count += 3; |
| 3608 break; |
| 3609 case '/': |
| 3610 if (outputBuf) { |
| 3611 strcpy(walkOutput, "%2F"); |
| 3612 walkOutput += 3; |
| 3613 } |
| 3614 count += 3; |
| 3615 break; |
| 3616 case '=': |
| 3617 if (outputBuf) { |
| 3618 strcpy(walkOutput, "%3D"); |
| 3619 walkOutput += 3; |
| 3620 } |
| 3621 count += 3; |
| 3622 break; |
| 3623 default: |
| 3624 if (outputBuf) { |
| 3625 *walkOutput = *walkInput; |
| 3626 ++walkOutput; |
| 3627 } |
| 3628 ++count; |
| 3629 break; |
| 3630 } |
| 3631 } |
| 3632 if (outputBuf) { |
| 3633 *walkOutput = 0; |
| 3634 } |
| 3635 ++count; |
| 3636 return count; |
| 3637 } |
| 3638 |
| 3639 enum { max_get_request_size = 255 }; /* defined by RFC2560 */ |
| 3640 |
| 3641 static SECItem * |
| 3642 cert_GetOCSPResponse(PLArenaPool *arena, const char *location, |
| 3643 const SECItem *encodedRequest); |
| 3644 |
| 3509 static SECItem * | 3645 static SECItem * |
| 3510 ocsp_GetEncodedOCSPResponseFromRequest(PLArenaPool *arena, | 3646 ocsp_GetEncodedOCSPResponseFromRequest(PLArenaPool *arena, |
| 3511 CERTOCSPRequest *request, | 3647 CERTOCSPRequest *request, |
| 3512 const char *location, PRTime time, | 3648 const char *location, |
| 3649 » » » » const char *method, |
| 3650 » » » » PRTime time, |
| 3513 PRBool addServiceLocator, | 3651 PRBool addServiceLocator, |
| 3514 void *pwArg, | 3652 void *pwArg, |
| 3515 CERTOCSPRequest **pRequest) | 3653 CERTOCSPRequest **pRequest) |
| 3516 { | 3654 { |
| 3517 SECItem *encodedRequest = NULL; | 3655 SECItem *encodedRequest = NULL; |
| 3518 SECItem *encodedResponse = NULL; | 3656 SECItem *encodedResponse = NULL; |
| 3519 SECStatus rv; | 3657 SECStatus rv; |
| 3520 | 3658 |
| 3659 if (!location || !*location) /* location should be at least one byte */ |
| 3660 goto loser; |
| 3661 |
| 3521 rv = CERT_AddOCSPAcceptableResponses(request, | 3662 rv = CERT_AddOCSPAcceptableResponses(request, |
| 3522 SEC_OID_PKIX_OCSP_BASIC_RESPONSE); | 3663 SEC_OID_PKIX_OCSP_BASIC_RESPONSE); |
| 3523 if (rv != SECSuccess) | 3664 if (rv != SECSuccess) |
| 3524 goto loser; | 3665 goto loser; |
| 3525 | 3666 |
| 3526 encodedRequest = CERT_EncodeOCSPRequest(NULL, request, pwArg); | 3667 encodedRequest = CERT_EncodeOCSPRequest(NULL, request, pwArg); |
| 3527 if (encodedRequest == NULL) | 3668 if (encodedRequest == NULL) |
| 3528 goto loser; | 3669 goto loser; |
| 3529 | 3670 |
| 3530 encodedResponse = CERT_PostOCSPRequest(arena, location, encodedRequest); | 3671 if (!strcmp(method, "GET")) { |
| 3672 encodedResponse = cert_GetOCSPResponse(arena, location, encodedRequest); |
| 3673 } |
| 3674 else if (!strcmp(method, "POST")) { |
| 3675 encodedResponse = CERT_PostOCSPRequest(arena, location, encodedRequest); |
| 3676 } |
| 3677 else { |
| 3678 » goto loser; |
| 3679 } |
| 3531 | 3680 |
| 3532 if (encodedResponse != NULL && pRequest != NULL) { | 3681 if (encodedResponse != NULL && pRequest != NULL) { |
| 3533 *pRequest = request; | 3682 *pRequest = request; |
| 3534 request = NULL; /* avoid destroying below */ | 3683 request = NULL; /* avoid destroying below */ |
| 3535 } | 3684 } |
| 3536 | 3685 |
| 3537 loser: | 3686 loser: |
| 3538 if (request != NULL) | 3687 if (request != NULL) |
| 3539 CERT_DestroyOCSPRequest(request); | 3688 CERT_DestroyOCSPRequest(request); |
| 3540 if (encodedRequest != NULL) | 3689 if (encodedRequest != NULL) |
| 3541 SECITEM_FreeItem(encodedRequest, PR_TRUE); | 3690 SECITEM_FreeItem(encodedRequest, PR_TRUE); |
| 3691 return encodedResponse; |
| 3692 } |
| 3542 | 3693 |
| 3543 return encodedResponse; | 3694 static SECItem * |
| 3695 cert_FetchOCSPResponse(PLArenaPool *arena, const char *location, |
| 3696 const SECItem *encodedRequest); |
| 3697 |
| 3698 /* using HTTP GET method */ |
| 3699 static SECItem * |
| 3700 cert_GetOCSPResponse(PLArenaPool *arena, const char *location, |
| 3701 const SECItem *encodedRequest) |
| 3702 { |
| 3703 char *walkOutput = NULL; |
| 3704 char *fullGetPath = NULL; |
| 3705 size_t pathLength; |
| 3706 PRInt32 urlEncodedBufLength; |
| 3707 size_t base64size; |
| 3708 char b64ReqBuf[max_get_request_size+1]; |
| 3709 size_t slashLengthIfNeeded = 0; |
| 3710 size_t getURLLength; |
| 3711 SECItem *item; |
| 3712 |
| 3713 if (!location || !*location) { |
| 3714 » return NULL; |
| 3715 } |
| 3716 |
| 3717 pathLength = strlen(location); |
| 3718 if (location[pathLength-1] != '/') { |
| 3719 » slashLengthIfNeeded = 1; |
| 3720 } |
| 3721 |
| 3722 /* Calculation as documented by PL_Base64Encode function. |
| 3723 * Use integer conversion to avoid having to use function ceil(). |
| 3724 */ |
| 3725 base64size = (((encodedRequest->len +2)/3) * 4); |
| 3726 if (base64size > max_get_request_size) { |
| 3727 » return NULL; |
| 3728 } |
| 3729 memset(b64ReqBuf, 0, sizeof(b64ReqBuf)); |
| 3730 PL_Base64Encode((const char*)encodedRequest->data, encodedRequest->len, |
| 3731 » » b64ReqBuf); |
| 3732 |
| 3733 urlEncodedBufLength = ocsp_UrlEncodeBase64Buf(b64ReqBuf, NULL); |
| 3734 getURLLength = pathLength + urlEncodedBufLength + slashLengthIfNeeded; |
| 3735 |
| 3736 /* urlEncodedBufLength already contains room for the zero terminator. |
| 3737 * Add another if we must add the '/' char. |
| 3738 */ |
| 3739 if (arena) { |
| 3740 fullGetPath = (char*)PORT_ArenaAlloc(arena, getURLLength); |
| 3741 } else { |
| 3742 fullGetPath = (char*)PORT_Alloc(getURLLength); |
| 3743 } |
| 3744 if (!fullGetPath) { |
| 3745 » return NULL; |
| 3746 } |
| 3747 |
| 3748 strcpy(fullGetPath, location); |
| 3749 walkOutput = fullGetPath + pathLength; |
| 3750 |
| 3751 if (walkOutput > fullGetPath && slashLengthIfNeeded) { |
| 3752 strcpy(walkOutput, "/"); |
| 3753 ++walkOutput; |
| 3754 } |
| 3755 ocsp_UrlEncodeBase64Buf(b64ReqBuf, walkOutput); |
| 3756 |
| 3757 item = cert_FetchOCSPResponse(arena, fullGetPath, NULL); |
| 3758 if (!arena) { |
| 3759 » PORT_Free(fullGetPath); |
| 3760 } |
| 3761 return item; |
| 3544 } | 3762 } |
| 3545 | 3763 |
| 3546 SECItem * | 3764 SECItem * |
| 3547 CERT_PostOCSPRequest(PLArenaPool *arena, const char *location, | 3765 CERT_PostOCSPRequest(PLArenaPool *arena, const char *location, |
| 3548 const SECItem *encodedRequest) | 3766 const SECItem *encodedRequest) |
| 3549 { | 3767 { |
| 3768 return cert_FetchOCSPResponse(arena, location, encodedRequest); |
| 3769 } |
| 3770 |
| 3771 SECItem * |
| 3772 cert_FetchOCSPResponse(PLArenaPool *arena, const char *location, |
| 3773 const SECItem *encodedRequest) |
| 3774 { |
| 3550 const SEC_HttpClientFcn *registeredHttpClient; | 3775 const SEC_HttpClientFcn *registeredHttpClient; |
| 3551 SECItem *encodedResponse = NULL; | 3776 SECItem *encodedResponse = NULL; |
| 3552 | 3777 |
| 3553 registeredHttpClient = SEC_GetRegisteredHttpClient(); | 3778 registeredHttpClient = SEC_GetRegisteredHttpClient(); |
| 3554 | 3779 |
| 3555 if (registeredHttpClient && registeredHttpClient->version == 1) { | 3780 if (registeredHttpClient && registeredHttpClient->version == 1) { |
| 3556 encodedResponse = fetchOcspHttpClientV1( | 3781 encodedResponse = fetchOcspHttpClientV1( |
| 3557 arena, | 3782 arena, |
| 3558 ®isteredHttpClient->fcnTable.ftable1, | 3783 ®isteredHttpClient->fcnTable.ftable1, |
| 3559 location, | 3784 location, |
| 3560 encodedRequest); | 3785 encodedRequest); |
| 3561 } else { | 3786 } else { |
| 3562 /* use internal http client */ | 3787 /* use internal http client */ |
| 3563 PRFileDesc *sock = ocsp_SendEncodedRequest(location, encodedRequest); | 3788 PRFileDesc *sock = ocsp_SendEncodedRequest(location, encodedRequest); |
| 3564 if (sock) { | 3789 if (sock) { |
| 3565 encodedResponse = ocsp_GetEncodedResponse(arena, sock); | 3790 encodedResponse = ocsp_GetEncodedResponse(arena, sock); |
| 3566 PR_Close(sock); | 3791 PR_Close(sock); |
| 3567 } | 3792 } |
| 3568 } | 3793 } |
| 3569 | 3794 |
| 3570 return encodedResponse; | 3795 return encodedResponse; |
| 3571 } | 3796 } |
| 3572 | 3797 |
| 3573 static SECItem * | 3798 static SECItem * |
| 3574 ocsp_GetEncodedOCSPResponseForSingleCert(PLArenaPool *arena, | 3799 ocsp_GetEncodedOCSPResponseForSingleCert(PLArenaPool *arena, |
| 3575 CERTOCSPCertID *certID, | 3800 CERTOCSPCertID *certID, |
| 3576 CERTCertificate *singleCert, | 3801 CERTCertificate *singleCert, |
| 3577 const char *location, PRTime time, | 3802 const char *location, |
| 3803 » » » » » const char *method, |
| 3804 » » » » » PRTime time, |
| 3578 PRBool addServiceLocator, | 3805 PRBool addServiceLocator, |
| 3579 void *pwArg, | 3806 void *pwArg, |
| 3580 CERTOCSPRequest **pRequest) | 3807 CERTOCSPRequest **pRequest) |
| 3581 { | 3808 { |
| 3582 CERTOCSPRequest *request; | 3809 CERTOCSPRequest *request; |
| 3583 request = cert_CreateSingleCertOCSPRequest(certID, singleCert, time, | 3810 request = cert_CreateSingleCertOCSPRequest(certID, singleCert, time, |
| 3584 addServiceLocator, NULL); | 3811 addServiceLocator, NULL); |
| 3585 if (!request) | 3812 if (!request) |
| 3586 return NULL; | 3813 return NULL; |
| 3587 return ocsp_GetEncodedOCSPResponseFromRequest(arena, request, location, | 3814 return ocsp_GetEncodedOCSPResponseFromRequest(arena, request, location, |
| 3588 time, addServiceLocator, | 3815 method, time, addServiceLocato
r, |
| 3589 pwArg, pRequest); | 3816 pwArg, pRequest); |
| 3590 } | 3817 } |
| 3591 | 3818 |
| 3592 /* Checks a certificate for the key usage extension of OCSP signer. */ | 3819 /* Checks a certificate for the key usage extension of OCSP signer. */ |
| 3593 static PRBool | 3820 static PRBool |
| 3594 ocsp_CertIsOCSPDesignatedResponder(CERTCertificate *cert) | 3821 ocsp_CertIsOCSPDesignatedResponder(CERTCertificate *cert) |
| 3595 { | 3822 { |
| 3596 SECStatus rv; | 3823 SECStatus rv; |
| 3597 SECItem extItem; | 3824 SECItem extItem; |
| 3598 SECItem **oids; | 3825 SECItem **oids; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3669 | 3896 |
| 3670 static PRBool | 3897 static PRBool |
| 3671 ocsp_matchcert(SECItem *certIndex,CERTCertificate *testCert) | 3898 ocsp_matchcert(SECItem *certIndex,CERTCertificate *testCert) |
| 3672 { | 3899 { |
| 3673 SECItem item; | 3900 SECItem item; |
| 3674 unsigned char buf[HASH_LENGTH_MAX]; | 3901 unsigned char buf[HASH_LENGTH_MAX]; |
| 3675 | 3902 |
| 3676 item.data = buf; | 3903 item.data = buf; |
| 3677 item.len = SHA1_LENGTH; | 3904 item.len = SHA1_LENGTH; |
| 3678 | 3905 |
| 3679 if (CERT_GetSPKIDigest(NULL,testCert,SEC_OID_SHA1, &item) == NULL) { | 3906 if (CERT_GetSubjectPublicKeyDigest(NULL,testCert,SEC_OID_SHA1, |
| 3907 » » » » &item) == NULL) { |
| 3680 return PR_FALSE; | 3908 return PR_FALSE; |
| 3681 } | 3909 } |
| 3682 if (SECITEM_ItemsAreEqual(certIndex,&item)) { | 3910 if (SECITEM_ItemsAreEqual(certIndex,&item)) { |
| 3683 return PR_TRUE; | 3911 return PR_TRUE; |
| 3684 } | 3912 } |
| 3685 if (CERT_GetSPKIDigest(NULL,testCert,SEC_OID_MD5, &item) == NULL) { | 3913 if (CERT_GetSubjectPublicKeyDigest(NULL,testCert,SEC_OID_MD5, |
| 3914 » » » » &item) == NULL) { |
| 3686 return PR_FALSE; | 3915 return PR_FALSE; |
| 3687 } | 3916 } |
| 3688 if (SECITEM_ItemsAreEqual(certIndex,&item)) { | 3917 if (SECITEM_ItemsAreEqual(certIndex,&item)) { |
| 3689 return PR_TRUE; | 3918 return PR_TRUE; |
| 3690 } | 3919 } |
| 3691 if (CERT_GetSPKIDigest(NULL,testCert,SEC_OID_MD2, &item) == NULL) { | 3920 if (CERT_GetSubjectPublicKeyDigest(NULL,testCert,SEC_OID_MD2, |
| 3921 » » » » &item) == NULL) { |
| 3692 return PR_FALSE; | 3922 return PR_FALSE; |
| 3693 } | 3923 } |
| 3694 if (SECITEM_ItemsAreEqual(certIndex,&item)) { | 3924 if (SECITEM_ItemsAreEqual(certIndex,&item)) { |
| 3695 return PR_TRUE; | 3925 return PR_TRUE; |
| 3696 } | 3926 } |
| 3697 | 3927 |
| 3698 return PR_FALSE; | 3928 return PR_FALSE; |
| 3699 } | 3929 } |
| 3700 | 3930 |
| 3701 static CERTCertificate * | 3931 static CERTCertificate * |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3782 if (responder && ocsp_matchcert(certIndex,responder)) { | 4012 if (responder && ocsp_matchcert(certIndex,responder)) { |
| 3783 signerCert = CERT_DupCertificate(responder); | 4013 signerCert = CERT_DupCertificate(responder); |
| 3784 } else if (issuer && ocsp_matchcert(certIndex,issuer)) { | 4014 } else if (issuer && ocsp_matchcert(certIndex,issuer)) { |
| 3785 signerCert = CERT_DupCertificate(issuer); | 4015 signerCert = CERT_DupCertificate(issuer); |
| 3786 } | 4016 } |
| 3787 for (i=0; (signerCert == NULL) && (i < certCount); i++) { | 4017 for (i=0; (signerCert == NULL) && (i < certCount); i++) { |
| 3788 if (ocsp_matchcert(certIndex,certs[i])) { | 4018 if (ocsp_matchcert(certIndex,certs[i])) { |
| 3789 signerCert = CERT_DupCertificate(certs[i]); | 4019 signerCert = CERT_DupCertificate(certs[i]); |
| 3790 } | 4020 } |
| 3791 } | 4021 } |
| 4022 if (signerCert == NULL) { |
| 4023 PORT_SetError(SEC_ERROR_UNKNOWN_CERT); |
| 4024 } |
| 3792 } | 4025 } |
| 3793 | 4026 |
| 3794 finish: | 4027 finish: |
| 3795 if (certs != NULL) { | 4028 if (certs != NULL) { |
| 3796 CERT_DestroyCertArray(certs, certCount); | 4029 CERT_DestroyCertArray(certs, certCount); |
| 3797 } | 4030 } |
| 3798 | 4031 |
| 3799 return signerCert; | 4032 return signerCert; |
| 3800 } | 4033 } |
| 3801 | 4034 |
| (...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4231 * | 4464 * |
| 4232 * First, lets check if signer of the response is the actual issuer | 4465 * First, lets check if signer of the response is the actual issuer |
| 4233 * of the cert. For that we will use signer cert key hash and cert subj | 4466 * of the cert. For that we will use signer cert key hash and cert subj |
| 4234 * name hash and will compare them with already calculated issuer key | 4467 * name hash and will compare them with already calculated issuer key |
| 4235 * hash and issuer name hash. The hash algorithm is picked from response | 4468 * hash and issuer name hash. The hash algorithm is picked from response |
| 4236 * certID hash to avoid second hash calculation. | 4469 * certID hash to avoid second hash calculation. |
| 4237 */ | 4470 */ |
| 4238 | 4471 |
| 4239 hashAlg = SECOID_FindOIDTag(&certID->hashAlgorithm.algorithm); | 4472 hashAlg = SECOID_FindOIDTag(&certID->hashAlgorithm.algorithm); |
| 4240 | 4473 |
| 4241 keyHash = CERT_GetSPKIDigest(NULL, signerCert, hashAlg, NULL); | 4474 keyHash = CERT_GetSubjectPublicKeyDigest(NULL, signerCert, hashAlg, NULL); |
| 4242 if (keyHash != NULL) { | 4475 if (keyHash != NULL) { |
| 4243 | 4476 |
| 4244 keyHashEQ = | 4477 keyHashEQ = |
| 4245 (SECITEM_CompareItem(keyHash, | 4478 (SECITEM_CompareItem(keyHash, |
| 4246 &certID->issuerKeyHash) == SECEqual); | 4479 &certID->issuerKeyHash) == SECEqual); |
| 4247 SECITEM_FreeItem(keyHash, PR_TRUE); | 4480 SECITEM_FreeItem(keyHash, PR_TRUE); |
| 4248 } | 4481 } |
| 4249 if (keyHashEQ && | 4482 if (keyHashEQ && |
| 4250 (nameHash = cert_GetSubjectNameDigest(NULL, signerCert, | 4483 (nameHash = CERT_GetSubjectNameDigest(NULL, signerCert, |
| 4251 hashAlg, NULL))) { | 4484 hashAlg, NULL))) { |
| 4252 nameHashEQ = | 4485 nameHashEQ = |
| 4253 (SECITEM_CompareItem(nameHash, | 4486 (SECITEM_CompareItem(nameHash, |
| 4254 &certID->issuerNameHash) == SECEqual); | 4487 &certID->issuerNameHash) == SECEqual); |
| 4255 | 4488 |
| 4256 SECITEM_FreeItem(nameHash, PR_TRUE); | 4489 SECITEM_FreeItem(nameHash, PR_TRUE); |
| 4257 if (nameHashEQ) { | 4490 if (nameHashEQ) { |
| 4258 /* The issuer of the cert is the the signer of the response */ | 4491 /* The issuer of the cert is the the signer of the response */ |
| 4259 return PR_TRUE; | 4492 return PR_TRUE; |
| 4260 } | 4493 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 4278 if (issuerCert == NULL) { | 4511 if (issuerCert == NULL) { |
| 4279 /* | 4512 /* |
| 4280 * We could leave the SEC_ERROR_UNKNOWN_ISSUER error alone, | 4513 * We could leave the SEC_ERROR_UNKNOWN_ISSUER error alone, |
| 4281 * but the following will give slightly more information. | 4514 * but the following will give slightly more information. |
| 4282 * Once we have an error stack, things will be much better. | 4515 * Once we have an error stack, things will be much better. |
| 4283 */ | 4516 */ |
| 4284 PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE); | 4517 PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE); |
| 4285 return PR_FALSE; | 4518 return PR_FALSE; |
| 4286 } | 4519 } |
| 4287 | 4520 |
| 4288 keyHash = CERT_GetSPKIDigest(NULL, issuerCert, hashAlg, NULL); | 4521 keyHash = CERT_GetSubjectPublicKeyDigest(NULL, issuerCert, hashAlg, NULL); |
| 4289 nameHash = cert_GetSubjectNameDigest(NULL, issuerCert, hashAlg, NULL); | 4522 nameHash = CERT_GetSubjectNameDigest(NULL, issuerCert, hashAlg, NULL); |
| 4290 | 4523 |
| 4291 CERT_DestroyCertificate(issuerCert); | 4524 CERT_DestroyCertificate(issuerCert); |
| 4292 | 4525 |
| 4293 if (keyHash != NULL && nameHash != NULL) { | 4526 if (keyHash != NULL && nameHash != NULL) { |
| 4294 keyHashEQ = | 4527 keyHashEQ = |
| 4295 (SECITEM_CompareItem(keyHash, | 4528 (SECITEM_CompareItem(keyHash, |
| 4296 &certID->issuerKeyHash) == SECEqual); | 4529 &certID->issuerKeyHash) == SECEqual); |
| 4297 | 4530 |
| 4298 nameHashEQ = | 4531 nameHashEQ = |
| 4299 (SECITEM_CompareItem(nameHash, | 4532 (SECITEM_CompareItem(nameHash, |
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4665 if (LL_CMP(revokedTime, >, time)) | 4898 if (LL_CMP(revokedTime, >, time)) |
| 4666 return SECSuccess; | 4899 return SECSuccess; |
| 4667 | 4900 |
| 4668 return SECFailure; | 4901 return SECFailure; |
| 4669 } | 4902 } |
| 4670 | 4903 |
| 4671 /* | 4904 /* |
| 4672 * See if the cert represented in the single response had a good status | 4905 * See if the cert represented in the single response had a good status |
| 4673 * at the specified time. | 4906 * at the specified time. |
| 4674 */ | 4907 */ |
| 4675 static SECStatus | 4908 SECStatus |
| 4676 ocsp_CertHasGoodStatus(ocspCertStatus *status, PRTime time) | 4909 ocsp_CertHasGoodStatus(ocspCertStatus *status, PRTime time) |
| 4677 { | 4910 { |
| 4678 SECStatus rv; | 4911 SECStatus rv; |
| 4679 switch (status->certStatusType) { | 4912 switch (status->certStatusType) { |
| 4680 case ocspCertStatus_good: | 4913 case ocspCertStatus_good: |
| 4681 rv = SECSuccess; | 4914 rv = SECSuccess; |
| 4682 break; | 4915 break; |
| 4683 case ocspCertStatus_revoked: | 4916 case ocspCertStatus_revoked: |
| 4684 rv = ocsp_CertRevokedAfter(status->certStatusInfo.revokedInfo, time); | 4917 rv = ocsp_CertRevokedAfter(status->certStatusInfo.revokedInfo, time); |
| 4685 break; | 4918 break; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 4697 return rv; | 4930 return rv; |
| 4698 } | 4931 } |
| 4699 | 4932 |
| 4700 static SECStatus | 4933 static SECStatus |
| 4701 ocsp_SingleResponseCertHasGoodStatus(CERTOCSPSingleResponse *single, | 4934 ocsp_SingleResponseCertHasGoodStatus(CERTOCSPSingleResponse *single, |
| 4702 PRTime time) | 4935 PRTime time) |
| 4703 { | 4936 { |
| 4704 return ocsp_CertHasGoodStatus(single->certStatus, time); | 4937 return ocsp_CertHasGoodStatus(single->certStatus, time); |
| 4705 } | 4938 } |
| 4706 | 4939 |
| 4707 /* Return value SECFailure means: not found or not fresh. | 4940 /* SECFailure means the arguments were invalid. |
| 4708 * On SECSuccess, the out parameters contain the OCSP status. | 4941 * On SECSuccess, the out parameters contain the OCSP status. |
| 4709 * rvOcsp contains the overall result of the OCSP operation. | 4942 * rvOcsp contains the overall result of the OCSP operation. |
| 4710 * Depending on input parameter ignoreGlobalOcspFailureSetting, | 4943 * Depending on input parameter ignoreGlobalOcspFailureSetting, |
| 4711 * a soft failure might be converted into *rvOcsp=SECSuccess. | 4944 * a soft failure might be converted into *rvOcsp=SECSuccess. |
| 4712 * If the cached attempt to obtain OCSP information had resulted | 4945 * If the cached attempt to obtain OCSP information had resulted |
| 4713 * in a failure, missingResponseError shows the error code of | 4946 * in a failure, missingResponseError shows the error code of |
| 4714 * that failure. | 4947 * that failure. |
| 4948 * cacheFreshness is ocspMissing if no entry was found, |
| 4949 * ocspFresh if a fresh entry was found, or |
| 4950 * ocspStale if a stale entry was found. |
| 4715 */ | 4951 */ |
| 4716 SECStatus | 4952 SECStatus |
| 4717 ocsp_GetCachedOCSPResponseStatusIfFresh(CERTOCSPCertID *certID, | 4953 ocsp_GetCachedOCSPResponseStatus(CERTOCSPCertID *certID, |
| 4718 PRTime time, | 4954 PRTime time, |
| 4719 PRBool ignoreGlobalOcspFailureSetting, | 4955 PRBool ignoreGlobalOcspFailureSetting, |
| 4720 SECStatus *rvOcsp, | 4956 SECStatus *rvOcsp, |
| 4721 SECErrorCodes *missingResponseError) | 4957 SECErrorCodes *missingResponseError, |
| 4958 OCSPFreshness *cacheFreshness) |
| 4722 { | 4959 { |
| 4723 OCSPCacheItem *cacheItem = NULL; | 4960 OCSPCacheItem *cacheItem = NULL; |
| 4724 SECStatus rv = SECFailure; | |
| 4725 | 4961 |
| 4726 if (!certID || !missingResponseError || !rvOcsp) { | 4962 if (!certID || !missingResponseError || !rvOcsp || !cacheFreshness) { |
| 4727 PORT_SetError(SEC_ERROR_INVALID_ARGS); | 4963 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
| 4728 return SECFailure; | 4964 return SECFailure; |
| 4729 } | 4965 } |
| 4730 *rvOcsp = SECFailure; | 4966 *rvOcsp = SECFailure; |
| 4731 *missingResponseError = 0; | 4967 *missingResponseError = 0; |
| 4968 *cacheFreshness = ocspMissing; |
| 4732 | 4969 |
| 4733 PR_EnterMonitor(OCSP_Global.monitor); | 4970 PR_EnterMonitor(OCSP_Global.monitor); |
| 4734 cacheItem = ocsp_FindCacheEntry(&OCSP_Global.cache, certID); | 4971 cacheItem = ocsp_FindCacheEntry(&OCSP_Global.cache, certID); |
| 4735 if (cacheItem && ocsp_IsCacheItemFresh(cacheItem)) { | 4972 if (cacheItem) { |
| 4973 *cacheFreshness = ocsp_IsCacheItemFresh(cacheItem) ? ocspFresh |
| 4974 : ocspStale; |
| 4736 /* having an arena means, we have a cached certStatus */ | 4975 /* having an arena means, we have a cached certStatus */ |
| 4737 if (cacheItem->certStatusArena) { | 4976 if (cacheItem->certStatusArena) { |
| 4738 *rvOcsp = ocsp_CertHasGoodStatus(&cacheItem->certStatus, time); | 4977 *rvOcsp = ocsp_CertHasGoodStatus(&cacheItem->certStatus, time); |
| 4739 if (*rvOcsp != SECSuccess) { | 4978 if (*rvOcsp != SECSuccess) { |
| 4740 *missingResponseError = PORT_GetError(); | 4979 *missingResponseError = PORT_GetError(); |
| 4741 } | 4980 } |
| 4742 rv = SECSuccess; | |
| 4743 } else { | 4981 } else { |
| 4744 /* | 4982 /* |
| 4745 * No status cached, the previous attempt failed. | 4983 * No status cached, the previous attempt failed. |
| 4746 * If OCSP is required, we never decide based on a failed attempt | 4984 * If OCSP is required, we never decide based on a failed attempt |
| 4747 * However, if OCSP is optional, a recent OCSP failure is | 4985 * However, if OCSP is optional, a recent OCSP failure is |
| 4748 * an allowed good state. | 4986 * an allowed good state. |
| 4749 */ | 4987 */ |
| 4750 if (!ignoreGlobalOcspFailureSetting && | 4988 if (*cacheFreshness == ocspFresh && |
| 4989 !ignoreGlobalOcspFailureSetting && |
| 4751 OCSP_Global.ocspFailureMode == | 4990 OCSP_Global.ocspFailureMode == |
| 4752 ocspMode_FailureIsNotAVerificationFailure) { | 4991 ocspMode_FailureIsNotAVerificationFailure) { |
| 4753 rv = SECSuccess; | |
| 4754 *rvOcsp = SECSuccess; | 4992 *rvOcsp = SECSuccess; |
| 4755 } | 4993 } |
| 4756 *missingResponseError = cacheItem->missingResponseError; | 4994 *missingResponseError = cacheItem->missingResponseError; |
| 4757 } | 4995 } |
| 4758 } | 4996 } |
| 4759 PR_ExitMonitor(OCSP_Global.monitor); | 4997 PR_ExitMonitor(OCSP_Global.monitor); |
| 4760 return rv; | 4998 return SECSuccess; |
| 4761 } | 4999 } |
| 4762 | 5000 |
| 4763 PRBool | 5001 PRBool |
| 4764 ocsp_FetchingFailureIsVerificationFailure(void) | 5002 ocsp_FetchingFailureIsVerificationFailure(void) |
| 4765 { | 5003 { |
| 4766 PRBool isFailure; | 5004 PRBool isFailure; |
| 4767 | 5005 |
| 4768 PR_EnterMonitor(OCSP_Global.monitor); | 5006 PR_EnterMonitor(OCSP_Global.monitor); |
| 4769 isFailure = | 5007 isFailure = |
| 4770 OCSP_Global.ocspFailureMode == ocspMode_FailureIsVerificationFailure; | 5008 OCSP_Global.ocspFailureMode == ocspMode_FailureIsVerificationFailure; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4821 * (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when | 5059 * (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when |
| 4822 * verifying the signer's cert, or low-level problems (error allocating | 5060 * verifying the signer's cert, or low-level problems (error allocating |
| 4823 * memory, error performing ASN.1 decoding, etc.). | 5061 * memory, error performing ASN.1 decoding, etc.). |
| 4824 */ | 5062 */ |
| 4825 SECStatus | 5063 SECStatus |
| 4826 CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert, | 5064 CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert, |
| 4827 PRTime time, void *pwArg) | 5065 PRTime time, void *pwArg) |
| 4828 { | 5066 { |
| 4829 CERTOCSPCertID *certID; | 5067 CERTOCSPCertID *certID; |
| 4830 PRBool certIDWasConsumed = PR_FALSE; | 5068 PRBool certIDWasConsumed = PR_FALSE; |
| 4831 SECStatus rv = SECFailure; | 5069 SECStatus rv; |
| 4832 SECStatus rvOcsp; | 5070 SECStatus rvOcsp; |
| 4833 SECErrorCodes dummy_error_code; /* we ignore this */ | 5071 SECErrorCodes cachedErrorCode; |
| 5072 OCSPFreshness cachedResponseFreshness; |
| 4834 | 5073 |
| 4835 OCSP_TRACE_CERT(cert); | 5074 OCSP_TRACE_CERT(cert); |
| 4836 OCSP_TRACE_TIME("## requested validity time:", time); | 5075 OCSP_TRACE_TIME("## requested validity time:", time); |
| 4837 | 5076 |
| 4838 certID = CERT_CreateOCSPCertID(cert, time); | 5077 certID = CERT_CreateOCSPCertID(cert, time); |
| 4839 if (!certID) | 5078 if (!certID) |
| 4840 return SECFailure; | 5079 return SECFailure; |
| 4841 rv = ocsp_GetCachedOCSPResponseStatusIfFresh( | 5080 rv = ocsp_GetCachedOCSPResponseStatus( |
| 4842 certID, time, PR_FALSE, /* ignoreGlobalOcspFailureSetting */ | 5081 certID, time, PR_FALSE, /* ignoreGlobalOcspFailureSetting */ |
| 4843 &rvOcsp, &dummy_error_code); | 5082 &rvOcsp, &cachedErrorCode, &cachedResponseFreshness); |
| 4844 if (rv == SECSuccess) { | 5083 if (rv != SECSuccess) { |
| 5084 CERT_DestroyOCSPCertID(certID); |
| 5085 return SECFailure; |
| 5086 } |
| 5087 if (cachedResponseFreshness == ocspFresh) { |
| 4845 CERT_DestroyOCSPCertID(certID); | 5088 CERT_DestroyOCSPCertID(certID); |
| 4846 return rvOcsp; | 5089 return rvOcsp; |
| 4847 } | 5090 } |
| 4848 rv = ocsp_GetOCSPStatusFromNetwork(handle, certID, cert, time, pwArg, | 5091 |
| 5092 rv = ocsp_GetOCSPStatusFromNetwork(handle, certID, cert, time, pwArg, |
| 4849 &certIDWasConsumed, | 5093 &certIDWasConsumed, |
| 4850 &rvOcsp); | 5094 &rvOcsp); |
| 4851 if (rv != SECSuccess) { | 5095 if (rv != SECSuccess) { |
| 4852 /* we were unable to obtain ocsp status. Check if we should | 5096 PRErrorCode err = PORT_GetError(); |
| 4853 * return cert status revoked. */ | 5097 if (ocsp_FetchingFailureIsVerificationFailure()) { |
| 4854 rvOcsp = ocsp_FetchingFailureIsVerificationFailure() ? | 5098 PORT_SetError(err); |
| 4855 SECFailure : SECSuccess; | 5099 rvOcsp = SECFailure; |
| 5100 } else if (cachedResponseFreshness == ocspStale && |
| 5101 (cachedErrorCode == SEC_ERROR_OCSP_UNKNOWN_CERT || |
| 5102 cachedErrorCode == SEC_ERROR_REVOKED_CERTIFICATE)) { |
| 5103 /* If we couldn't get a response for a certificate that the OCSP |
| 5104 * responder previously told us was bad, then assume it is still |
| 5105 * bad until we hear otherwise, as it is very unlikely that the |
| 5106 * certificate status has changed from "revoked" to "good" and it |
| 5107 * is also unlikely that the certificate status has changed from |
| 5108 * "unknown" to "good", except for some buggy OCSP responders. |
| 5109 */ |
| 5110 PORT_SetError(cachedErrorCode); |
| 5111 rvOcsp = SECFailure; |
| 5112 } else { |
| 5113 rvOcsp = SECSuccess; |
| 5114 } |
| 4856 } | 5115 } |
| 4857 if (!certIDWasConsumed) { | 5116 if (!certIDWasConsumed) { |
| 4858 CERT_DestroyOCSPCertID(certID); | 5117 CERT_DestroyOCSPCertID(certID); |
| 4859 } | 5118 } |
| 4860 return rvOcsp; | 5119 return rvOcsp; |
| 4861 } | 5120 } |
| 4862 | 5121 |
| 4863 /* | 5122 /* |
| 4864 * FUNCTION: CERT_CacheOCSPResponseFromSideChannel | 5123 * FUNCTION: CERT_CacheOCSPResponseFromSideChannel |
| 4865 * First, this function checks the OCSP cache to see if a good response | 5124 * First, this function checks the OCSP cache to see if a good response |
| (...skipping 25 matching lines...) Expand all Loading... |
| 4891 SECStatus | 5150 SECStatus |
| 4892 CERT_CacheOCSPResponseFromSideChannel(CERTCertDBHandle *handle, | 5151 CERT_CacheOCSPResponseFromSideChannel(CERTCertDBHandle *handle, |
| 4893 CERTCertificate *cert, | 5152 CERTCertificate *cert, |
| 4894 PRTime time, | 5153 PRTime time, |
| 4895 const SECItem *encodedResponse, | 5154 const SECItem *encodedResponse, |
| 4896 void *pwArg) | 5155 void *pwArg) |
| 4897 { | 5156 { |
| 4898 CERTOCSPCertID *certID = NULL; | 5157 CERTOCSPCertID *certID = NULL; |
| 4899 PRBool certIDWasConsumed = PR_FALSE; | 5158 PRBool certIDWasConsumed = PR_FALSE; |
| 4900 SECStatus rv = SECFailure; | 5159 SECStatus rv = SECFailure; |
| 4901 SECStatus rvOcsp; | 5160 SECStatus rvOcsp = SECFailure; |
| 4902 SECErrorCodes dummy_error_code; /* we ignore this */ | 5161 SECErrorCodes dummy_error_code; /* we ignore this */ |
| 5162 CERTOCSPResponse *decodedResponse = NULL; |
| 5163 CERTOCSPSingleResponse *singleResponse = NULL; |
| 5164 OCSPFreshness freshness; |
| 4903 | 5165 |
| 4904 /* The OCSP cache can be in three states regarding this certificate: | 5166 /* The OCSP cache can be in three states regarding this certificate: |
| 4905 * + Good (cached, timely, 'good' response, or revoked in the future) | 5167 * + Good (cached, timely, 'good' response, or revoked in the future) |
| 4906 * + Revoked (cached, timely, but doesn't fit in the last category) | 5168 * + Revoked (cached, timely, but doesn't fit in the last category) |
| 4907 * + Miss (no knowledge) | 5169 * + Miss (no knowledge) |
| 4908 * | 5170 * |
| 4909 * Likewise, the side-channel information can be | 5171 * Likewise, the side-channel information can be |
| 4910 * + Good (timely, 'good' response, or revoked in the future) | 5172 * + Good (timely, 'good' response, or revoked in the future) |
| 4911 * + Revoked (timely, but doesn't fit in the last category) | 5173 * + Revoked (timely, but doesn't fit in the last category) |
| 4912 * + Invalid (bad syntax, bad signature, not timely etc) | 5174 * + Invalid (bad syntax, bad signature, not timely etc) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 4933 * e | | 5195 * e | |
| 4934 * l | | 5196 * l | |
| 4935 * | 5197 * |
| 4936 * When we fetch from the network we might choose to cache a negative | 5198 * When we fetch from the network we might choose to cache a negative |
| 4937 * result when the response is invalid. This saves us hammering, uselessly, | 5199 * result when the response is invalid. This saves us hammering, uselessly, |
| 4938 * at a broken responder. However, side channels are commonly attacker | 5200 * at a broken responder. However, side channels are commonly attacker |
| 4939 * controlled and so we must not cache a negative result for an Invalid | 5201 * controlled and so we must not cache a negative result for an Invalid |
| 4940 * side channel. | 5202 * side channel. |
| 4941 */ | 5203 */ |
| 4942 | 5204 |
| 4943 if (!cert) { | 5205 if (!cert || !encodedResponse) { |
| 4944 PORT_SetError(SEC_ERROR_INVALID_ARGS); | 5206 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
| 4945 return SECFailure; | 5207 return SECFailure; |
| 4946 } | 5208 } |
| 4947 certID = CERT_CreateOCSPCertID(cert, time); | 5209 certID = CERT_CreateOCSPCertID(cert, time); |
| 4948 if (!certID) | 5210 if (!certID) |
| 4949 return SECFailure; | 5211 return SECFailure; |
| 4950 rv = ocsp_GetCachedOCSPResponseStatusIfFresh( | 5212 |
| 4951 certID, time, PR_FALSE, /* ignoreGlobalOcspFailureSetting */ | 5213 /* We pass PR_TRUE for ignoreGlobalOcspFailureSetting so that a cached |
| 4952 &rvOcsp, &dummy_error_code); | 5214 * error entry is not interpreted as being a 'Good' entry here. |
| 4953 if (rv == SECSuccess && rvOcsp == SECSuccess) { | 5215 */ |
| 5216 rv = ocsp_GetCachedOCSPResponseStatus( |
| 5217 certID, time, PR_TRUE, /* ignoreGlobalOcspFailureSetting */ |
| 5218 &rvOcsp, &dummy_error_code, &freshness); |
| 5219 if (rv == SECSuccess && rvOcsp == SECSuccess && freshness == ocspFresh) { |
| 4954 /* The cached value is good. We don't want to waste time validating | 5220 /* The cached value is good. We don't want to waste time validating |
| 4955 * this OCSP response. This is the first column in the table above. */ | 5221 * this OCSP response. This is the first column in the table above. */ |
| 4956 CERT_DestroyOCSPCertID(certID); | 5222 CERT_DestroyOCSPCertID(certID); |
| 4957 return rv; | 5223 return rv; |
| 4958 } | 5224 } |
| 4959 | 5225 |
| 4960 /* The logic for caching the more recent response is handled in | 5226 /* The logic for caching the more recent response is handled in |
| 4961 * ocsp_CreateOrUpdateCacheEntry, which is called by this function. */ | 5227 * ocsp_CacheSingleResponse. */ |
| 4962 rv = ocsp_CacheEncodedOCSPResponse(handle, certID, cert, time, | 5228 |
| 4963 pwArg, encodedResponse, | 5229 rv = ocsp_GetDecodedVerifiedSingleResponseForID(handle, certID, cert, |
| 4964 PR_FALSE /* don't cache if invalid */, | 5230 » » » » » » time, pwArg, |
| 4965 &certIDWasConsumed, | 5231 » » » » » » encodedResponse, |
| 4966 &rvOcsp); | 5232 » » » » » » &decodedResponse, |
| 5233 » » » » » » &singleResponse); |
| 5234 if (rv == SECSuccess) { |
| 5235 » rvOcsp = ocsp_SingleResponseCertHasGoodStatus(singleResponse, time); |
| 5236 » /* Cache any valid singleResponse, regardless of status. */ |
| 5237 » ocsp_CacheSingleResponse(certID, singleResponse, &certIDWasConsumed); |
| 5238 } |
| 5239 if (decodedResponse) { |
| 5240 » CERT_DestroyOCSPResponse(decodedResponse); |
| 5241 } |
| 4967 if (!certIDWasConsumed) { | 5242 if (!certIDWasConsumed) { |
| 4968 CERT_DestroyOCSPCertID(certID); | 5243 CERT_DestroyOCSPCertID(certID); |
| 4969 } | 5244 } |
| 4970 return rv == SECSuccess ? rvOcsp : rv; | 5245 return rv == SECSuccess ? rvOcsp : rv; |
| 4971 } | 5246 } |
| 4972 | 5247 |
| 4973 /* | 5248 /* |
| 4974 * Status in *certIDWasConsumed will always be correct, regardless of | 5249 * Status in *certIDWasConsumed will always be correct, regardless of |
| 4975 * return value. | 5250 * return value. |
| 4976 */ | 5251 */ |
| 4977 static SECStatus | 5252 static SECStatus |
| 4978 ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle *handle, | 5253 ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle *handle, |
| 4979 CERTOCSPCertID *certID, | 5254 CERTOCSPCertID *certID, |
| 4980 CERTCertificate *cert, | 5255 CERTCertificate *cert, |
| 4981 PRTime time, | 5256 PRTime time, |
| 4982 void *pwArg, | 5257 void *pwArg, |
| 4983 PRBool *certIDWasConsumed, | 5258 PRBool *certIDWasConsumed, |
| 4984 SECStatus *rv_ocsp) | 5259 SECStatus *rv_ocsp) |
| 4985 { | 5260 { |
| 4986 char *location = NULL; | 5261 char *location = NULL; |
| 4987 PRBool locationIsDefault; | 5262 PRBool locationIsDefault; |
| 4988 SECItem *encodedResponse = NULL; | 5263 SECItem *encodedResponse = NULL; |
| 4989 CERTOCSPRequest *request = NULL; | 5264 CERTOCSPRequest *request = NULL; |
| 4990 SECStatus rv = SECFailure; | 5265 SECStatus rv = SECFailure; |
| 4991 | 5266 |
| 5267 CERTOCSPResponse *decodedResponse = NULL; |
| 5268 CERTOCSPSingleResponse *singleResponse = NULL; |
| 5269 enum { stageGET, stagePOST } currentStage; |
| 5270 PRBool retry = PR_FALSE; |
| 5271 |
| 4992 if (!certIDWasConsumed || !rv_ocsp) { | 5272 if (!certIDWasConsumed || !rv_ocsp) { |
| 4993 PORT_SetError(SEC_ERROR_INVALID_ARGS); | 5273 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
| 4994 return SECFailure; | 5274 return SECFailure; |
| 4995 } | 5275 } |
| 4996 *certIDWasConsumed = PR_FALSE; | 5276 *certIDWasConsumed = PR_FALSE; |
| 4997 *rv_ocsp = SECFailure; | 5277 *rv_ocsp = SECFailure; |
| 4998 | 5278 |
| 5279 if (!OCSP_Global.monitor) { |
| 5280 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); |
| 5281 return SECFailure; |
| 5282 } |
| 5283 PR_EnterMonitor(OCSP_Global.monitor); |
| 5284 if (OCSP_Global.forcePost) { |
| 5285 currentStage = stagePOST; |
| 5286 } else { |
| 5287 currentStage = stageGET; |
| 5288 } |
| 5289 PR_ExitMonitor(OCSP_Global.monitor); |
| 5290 |
| 4999 /* | 5291 /* |
| 5000 * The first thing we need to do is find the location of the responder. | 5292 * The first thing we need to do is find the location of the responder. |
| 5001 * This will be the value of the default responder (if enabled), else | 5293 * This will be the value of the default responder (if enabled), else |
| 5002 * it will come out of the AIA extension in the cert (if present). | 5294 * it will come out of the AIA extension in the cert (if present). |
| 5003 * If we have no such location, then this cert does not "deserve" to | 5295 * If we have no such location, then this cert does not "deserve" to |
| 5004 * be checked -- that is, we consider it a success and just return. | 5296 * be checked -- that is, we consider it a success and just return. |
| 5005 * The way we tell that is by looking at the error number to see if | 5297 * The way we tell that is by looking at the error number to see if |
| 5006 * the problem was no AIA extension was found; any other error was | 5298 * the problem was no AIA extension was found; any other error was |
| 5007 * a true failure that we unfortunately have to treat as an overall | 5299 * a true failure that we unfortunately have to treat as an overall |
| 5008 * failure here. | 5300 * failure here. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 5034 * because each issuer is different. Carefully read the OCSP spec | 5326 * because each issuer is different. Carefully read the OCSP spec |
| 5035 * if you do not understand this.) | 5327 * if you do not understand this.) |
| 5036 */ | 5328 */ |
| 5037 | 5329 |
| 5038 /* | 5330 /* |
| 5039 * XXX If/when signing of requests is supported, that second NULL | 5331 * XXX If/when signing of requests is supported, that second NULL |
| 5040 * should be changed to be the signer certificate. Not sure if that | 5332 * should be changed to be the signer certificate. Not sure if that |
| 5041 * should be passed into this function or retrieved via some operation | 5333 * should be passed into this function or retrieved via some operation |
| 5042 * on the handle/context. | 5334 * on the handle/context. |
| 5043 */ | 5335 */ |
| 5044 encodedResponse = | |
| 5045 ocsp_GetEncodedOCSPResponseForSingleCert(NULL, certID, cert, location, | |
| 5046 time, locationIsDefault, | |
| 5047 pwArg, &request); | |
| 5048 if (encodedResponse == NULL) { | |
| 5049 goto loser; | |
| 5050 } | |
| 5051 | 5336 |
| 5052 rv = ocsp_CacheEncodedOCSPResponse(handle, certID, cert, time, pwArg, | 5337 do { |
| 5053 encodedResponse, | 5338 » const char *method; |
| 5054 PR_TRUE /* cache if invalid */, | 5339 » PRBool validResponseWithAccurateInfo = PR_FALSE; |
| 5055 certIDWasConsumed, rv_ocsp); | 5340 » retry = PR_FALSE; |
| 5341 » *rv_ocsp = SECFailure; |
| 5056 | 5342 |
| 5057 loser: | 5343 » if (currentStage == stageGET) { |
| 5058 if (request != NULL) | 5344 » method = "GET"; |
| 5059 » CERT_DestroyOCSPRequest(request); | 5345 » } else { |
| 5060 if (encodedResponse != NULL) | 5346 » PORT_Assert(currentStage == stagePOST); |
| 5061 » SECITEM_FreeItem(encodedResponse, PR_TRUE); | 5347 » method = "POST"; |
| 5062 if (location != NULL) | 5348 » } |
| 5063 » PORT_Free(location); | |
| 5064 | 5349 |
| 5350 encodedResponse = |
| 5351 ocsp_GetEncodedOCSPResponseForSingleCert(NULL, certID, cert, |
| 5352 location, method, |
| 5353 time, locationIsDefault, |
| 5354 pwArg, &request); |
| 5355 |
| 5356 if (encodedResponse) { |
| 5357 rv = ocsp_GetDecodedVerifiedSingleResponseForID(handle, certID, cert
, |
| 5358 time, pwArg, |
| 5359 encodedResponse, |
| 5360 &decodedResponse, |
| 5361 &singleResponse); |
| 5362 if (rv == SECSuccess) { |
| 5363 switch (singleResponse->certStatus->certStatusType) { |
| 5364 case ocspCertStatus_good: |
| 5365 case ocspCertStatus_revoked: |
| 5366 validResponseWithAccurateInfo = PR_TRUE; |
| 5367 break; |
| 5368 default: |
| 5369 break; |
| 5370 } |
| 5371 *rv_ocsp = ocsp_SingleResponseCertHasGoodStatus(singleResponse,
time); |
| 5372 } |
| 5373 } |
| 5374 |
| 5375 if (currentStage == stageGET) { |
| 5376 /* only accept GET response if good or revoked */ |
| 5377 if (validResponseWithAccurateInfo) { |
| 5378 ocsp_CacheSingleResponse(certID, singleResponse, |
| 5379 certIDWasConsumed); |
| 5380 } else { |
| 5381 retry = PR_TRUE; |
| 5382 currentStage = stagePOST; |
| 5383 } |
| 5384 } else { |
| 5385 /* cache the POST respone, regardless of status */ |
| 5386 if (!singleResponse) { |
| 5387 cert_RememberOCSPProcessingFailure(certID, certIDWasConsumed); |
| 5388 } else { |
| 5389 ocsp_CacheSingleResponse(certID, singleResponse, |
| 5390 certIDWasConsumed); |
| 5391 } |
| 5392 } |
| 5393 |
| 5394 if (encodedResponse) { |
| 5395 SECITEM_FreeItem(encodedResponse, PR_TRUE); |
| 5396 encodedResponse = NULL; |
| 5397 } |
| 5398 if (request) { |
| 5399 CERT_DestroyOCSPRequest(request); |
| 5400 request = NULL; |
| 5401 } |
| 5402 if (decodedResponse) { |
| 5403 CERT_DestroyOCSPResponse(decodedResponse); |
| 5404 decodedResponse = NULL; |
| 5405 } |
| 5406 singleResponse = NULL; |
| 5407 |
| 5408 } while (retry); |
| 5409 |
| 5410 PORT_Free(location); |
| 5065 return rv; | 5411 return rv; |
| 5066 } | 5412 } |
| 5067 | 5413 |
| 5068 /* | 5414 /* |
| 5069 * FUNCTION: ocsp_CacheEncodedOCSPResponse | 5415 * FUNCTION: ocsp_GetDecodedVerifiedSingleResponseForID |
| 5070 * This function decodes an OCSP response and checks for a valid response | 5416 * This function decodes an OCSP response and checks for a valid response |
| 5071 * concerning the given certificate. If such a response is not found | 5417 * concerning the given certificate. |
| 5072 * then nothing is cached. Otherwise, if it is a good response, or if | |
| 5073 * cacheNegative is true, the results are stored in the OCSP cache. | |
| 5074 * | 5418 * |
| 5075 * Note: a 'valid' response is one that parses successfully, is not an OCSP | 5419 * Note: a 'valid' response is one that parses successfully, is not an OCSP |
| 5076 * exception (see RFC 2560 Section 2.3), is correctly signed and is current. | 5420 * exception (see RFC 2560 Section 2.3), is correctly signed and is current. |
| 5077 * A 'good' response is a valid response that attests that the certificate | 5421 * A 'good' response is a valid response that attests that the certificate |
| 5078 * is not currently revoked (see RFC 2560 Section 2.2). | 5422 * is not currently revoked (see RFC 2560 Section 2.2). |
| 5079 * | 5423 * |
| 5080 * INPUTS: | 5424 * INPUTS: |
| 5081 * CERTCertDBHandle *handle | 5425 * CERTCertDBHandle *handle |
| 5082 * certificate DB of the cert that is being checked | 5426 * certificate DB of the cert that is being checked |
| 5083 * CERTOCSPCertID *certID | 5427 * CERTOCSPCertID *certID |
| 5084 * the cert ID corresponding to |cert| | 5428 * the cert ID corresponding to |cert| |
| 5085 * CERTCertificate *cert | 5429 * CERTCertificate *cert |
| 5086 * the certificate being checked | 5430 * the certificate being checked |
| 5087 * PRTime time | 5431 * PRTime time |
| 5088 * time for which status is to be determined | 5432 * time for which status is to be determined |
| 5089 * void *pwArg | 5433 * void *pwArg |
| 5090 * the opaque argument to the password prompting function. | 5434 * the opaque argument to the password prompting function. |
| 5091 * SECItem *encodedResponse | 5435 * SECItem *encodedResponse |
| 5092 * the DER encoded bytes of the OCSP response | 5436 * the DER encoded bytes of the OCSP response |
| 5093 * PRBool cacheInvalid | 5437 * CERTOCSPResponse **pDecodedResponse |
| 5094 * If true then invalid responses will cause a negative cache entry to be | 5438 * (output) The caller must ALWAYS check for this output parameter, |
| 5095 * created. (Invalid means bad syntax, bad signature etc) | 5439 * and if it's non-null, must destroy it using CERT_DestroyOCSPResponse. |
| 5096 * PRBool *certIDWasConsumed | 5440 * CERTOCSPSingleResponse **pSingle |
| 5097 * (output) on return, this is true iff |certID| was consumed by this | 5441 * (output) on success, this points to the single response that corresponds |
| 5098 * function. | 5442 * to the certID parameter. Points to the inside of pDecodedResponse. |
| 5099 * SECStatus *rv_ocsp | 5443 * It isn't a copy, don't free it. |
| 5100 * (output) on return, this is SECSuccess iff the response is good (see | |
| 5101 * definition of 'good' above). | |
| 5102 * RETURN: | 5444 * RETURN: |
| 5103 * SECSuccess iff the response is valid. | 5445 * SECSuccess iff the response is valid. |
| 5104 */ | 5446 */ |
| 5105 static SECStatus | 5447 static SECStatus |
| 5106 ocsp_CacheEncodedOCSPResponse(CERTCertDBHandle *handle, | 5448 ocsp_GetDecodedVerifiedSingleResponseForID(CERTCertDBHandle *handle, |
| 5107 » » » CERTOCSPCertID *certID, | 5449 » » » » » CERTOCSPCertID *certID, |
| 5108 » » » CERTCertificate *cert, | 5450 » » » » » CERTCertificate *cert, |
| 5109 » » » PRTime time, | 5451 » » » » » PRTime time, |
| 5110 » » » void *pwArg, | 5452 » » » » » void *pwArg, |
| 5111 » » » const SECItem *encodedResponse, | 5453 » » » » » const SECItem *encodedResponse, |
| 5112 PRBool cacheInvalid, | 5454 » » » » » CERTOCSPResponse **pDecodedResponse, |
| 5113 » » » PRBool *certIDWasConsumed, | 5455 » » » » » CERTOCSPSingleResponse **pSingle) |
| 5114 » » » SECStatus *rv_ocsp) | |
| 5115 { | 5456 { |
| 5116 CERTOCSPResponse *response = NULL; | |
| 5117 CERTCertificate *signerCert = NULL; | 5457 CERTCertificate *signerCert = NULL; |
| 5118 CERTCertificate *issuerCert = NULL; | 5458 CERTCertificate *issuerCert = NULL; |
| 5119 CERTOCSPSingleResponse *single = NULL; | |
| 5120 SECStatus rv = SECFailure; | 5459 SECStatus rv = SECFailure; |
| 5121 | 5460 |
| 5122 *certIDWasConsumed = PR_FALSE; | 5461 if (!pSingle || !pDecodedResponse) { |
| 5123 *rv_ocsp = SECFailure; | 5462 » return SECFailure; |
| 5124 | 5463 } |
| 5125 response = CERT_DecodeOCSPResponse(encodedResponse); | 5464 *pSingle = NULL; |
| 5126 if (response == NULL) { | 5465 *pDecodedResponse = CERT_DecodeOCSPResponse(encodedResponse); |
| 5127 » goto loser; | 5466 if (!*pDecodedResponse) { |
| 5467 » return SECFailure; |
| 5128 } | 5468 } |
| 5129 | 5469 |
| 5130 /* | 5470 /* |
| 5131 * Okay, we at least have a response that *looks* like a response! | 5471 * Okay, we at least have a response that *looks* like a response! |
| 5132 * Now see if the overall response status value is good or not. | 5472 * Now see if the overall response status value is good or not. |
| 5133 * If not, we set an error and give up. (It means that either the | 5473 * If not, we set an error and give up. (It means that either the |
| 5134 * server had a problem, or it didn't like something about our | 5474 * server had a problem, or it didn't like something about our |
| 5135 * request. Either way there is nothing to do but give up.) | 5475 * request. Either way there is nothing to do but give up.) |
| 5136 * Otherwise, we continue to find the actual per-cert status | 5476 * Otherwise, we continue to find the actual per-cert status |
| 5137 * in the response. | 5477 * in the response. |
| 5138 */ | 5478 */ |
| 5139 if (CERT_GetOCSPResponseStatus(response) != SECSuccess) { | 5479 if (CERT_GetOCSPResponseStatus(*pDecodedResponse) != SECSuccess) { |
| 5140 goto loser; | 5480 goto loser; |
| 5141 } | 5481 } |
| 5142 | 5482 |
| 5143 /* | 5483 /* |
| 5144 * If we've made it this far, we expect a response with a good signature. | 5484 * If we've made it this far, we expect a response with a good signature. |
| 5145 * So, check for that. | 5485 * So, check for that. |
| 5146 */ | 5486 */ |
| 5147 issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA); | 5487 issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA); |
| 5148 rv = CERT_VerifyOCSPResponseSignature(response, handle, pwArg, &signerCert, | 5488 rv = CERT_VerifyOCSPResponseSignature(*pDecodedResponse, handle, pwArg, |
| 5149 » » » issuerCert); | 5489 &signerCert, issuerCert); |
| 5150 if (rv != SECSuccess) | 5490 if (rv != SECSuccess) { |
| 5151 goto loser; | 5491 goto loser; |
| 5492 } |
| 5152 | 5493 |
| 5153 PORT_Assert(signerCert != NULL); /* internal consistency check */ | 5494 PORT_Assert(signerCert != NULL); /* internal consistency check */ |
| 5154 /* XXX probably should set error, return failure if signerCert is null */ | 5495 /* XXX probably should set error, return failure if signerCert is null */ |
| 5155 | 5496 |
| 5156 | |
| 5157 /* | 5497 /* |
| 5158 * Again, we are only doing one request for one cert. | 5498 * Again, we are only doing one request for one cert. |
| 5159 * XXX When we handle cert chains, the following code will obviously | 5499 * XXX When we handle cert chains, the following code will obviously |
| 5160 * have to be modified, in coordation with the code above that will | 5500 * have to be modified, in coordation with the code above that will |
| 5161 * have to determine how to make multiple requests, etc. | 5501 * have to determine how to make multiple requests, etc. |
| 5162 */ | 5502 */ |
| 5503 rv = ocsp_GetVerifiedSingleResponseForCertID(handle, *pDecodedResponse, cert
ID, |
| 5504 signerCert, time, pSingle); |
| 5505 loser: |
| 5506 if (issuerCert != NULL) |
| 5507 CERT_DestroyCertificate(issuerCert); |
| 5508 if (signerCert != NULL) |
| 5509 CERT_DestroyCertificate(signerCert); |
| 5510 return rv; |
| 5511 } |
| 5163 | 5512 |
| 5164 rv = ocsp_GetVerifiedSingleResponseForCertID(handle, response, certID, | 5513 /* |
| 5165 signerCert, time, &single); | 5514 * FUNCTION: ocsp_CacheSingleResponse |
| 5166 if (rv != SECSuccess) | 5515 * This function requires that the caller has checked that the response |
| 5167 goto loser; | 5516 * is valid and verified. |
| 5168 | 5517 * The (positive or negative) valid response will be used to update the cache. |
| 5169 *rv_ocsp = ocsp_SingleResponseCertHasGoodStatus(single, time); | 5518 * INPUTS: |
| 5170 | 5519 * CERTOCSPCertID *certID |
| 5171 loser: | 5520 * the cert ID corresponding to |cert| |
| 5172 /* If single == NULL here then the response was invalid. */ | 5521 * PRBool *certIDWasConsumed |
| 5173 if (single != NULL || cacheInvalid) { | 5522 * (output) on return, this is true iff |certID| was consumed by this |
| 5523 * function. |
| 5524 */ |
| 5525 void |
| 5526 ocsp_CacheSingleResponse(CERTOCSPCertID *certID, |
| 5527 » » » CERTOCSPSingleResponse *single, |
| 5528 » » » PRBool *certIDWasConsumed) |
| 5529 { |
| 5530 if (single != NULL) { |
| 5174 PR_EnterMonitor(OCSP_Global.monitor); | 5531 PR_EnterMonitor(OCSP_Global.monitor); |
| 5175 if (OCSP_Global.maxCacheEntries >= 0) { | 5532 if (OCSP_Global.maxCacheEntries >= 0) { |
| 5176 /* single == NULL means: remember response failure */ | |
| 5177 ocsp_CreateOrUpdateCacheEntry(&OCSP_Global.cache, certID, single, | 5533 ocsp_CreateOrUpdateCacheEntry(&OCSP_Global.cache, certID, single, |
| 5178 certIDWasConsumed); | 5534 certIDWasConsumed); |
| 5179 /* ignore cache update failures */ | 5535 /* ignore cache update failures */ |
| 5180 } | 5536 } |
| 5181 PR_ExitMonitor(OCSP_Global.monitor); | 5537 PR_ExitMonitor(OCSP_Global.monitor); |
| 5182 } | 5538 } |
| 5183 | |
| 5184 /* 'single' points within the response so there's no need to free it. */ | |
| 5185 | |
| 5186 if (issuerCert != NULL) | |
| 5187 CERT_DestroyCertificate(issuerCert); | |
| 5188 if (signerCert != NULL) | |
| 5189 CERT_DestroyCertificate(signerCert); | |
| 5190 if (response != NULL) | |
| 5191 CERT_DestroyOCSPResponse(response); | |
| 5192 return rv; | |
| 5193 } | 5539 } |
| 5194 | 5540 |
| 5195 static SECStatus | 5541 SECStatus |
| 5196 ocsp_GetVerifiedSingleResponseForCertID(CERTCertDBHandle *handle, | 5542 ocsp_GetVerifiedSingleResponseForCertID(CERTCertDBHandle *handle, |
| 5197 CERTOCSPResponse *response, | 5543 CERTOCSPResponse *response, |
| 5198 CERTOCSPCertID *certID, | 5544 CERTOCSPCertID *certID, |
| 5199 CERTCertificate *signerCert, | 5545 CERTCertificate *signerCert, |
| 5200 PRTime time, | 5546 PRTime time, |
| 5201 CERTOCSPSingleResponse | 5547 CERTOCSPSingleResponse |
| 5202 **pSingleResponse) | 5548 **pSingleResponse) |
| 5203 { | 5549 { |
| 5204 SECStatus rv; | 5550 SECStatus rv; |
| 5205 ocspResponseData *responseData; | 5551 ocspResponseData *responseData; |
| (...skipping 572 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5778 CERT_ClearOCSPCache(); | 6124 CERT_ClearOCSPCache(); |
| 5779 } | 6125 } |
| 5780 | 6126 |
| 5781 /* | 6127 /* |
| 5782 * Finally, record the fact. | 6128 * Finally, record the fact. |
| 5783 */ | 6129 */ |
| 5784 statusContext->useDefaultResponder = PR_FALSE; | 6130 statusContext->useDefaultResponder = PR_FALSE; |
| 5785 return SECSuccess; | 6131 return SECSuccess; |
| 5786 } | 6132 } |
| 5787 | 6133 |
| 6134 SECStatus |
| 6135 CERT_ForcePostMethodForOCSP(PRBool forcePost) |
| 6136 { |
| 6137 if (!OCSP_Global.monitor) { |
| 6138 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); |
| 6139 return SECFailure; |
| 6140 } |
| 6141 |
| 6142 PR_EnterMonitor(OCSP_Global.monitor); |
| 6143 OCSP_Global.forcePost = forcePost; |
| 6144 PR_ExitMonitor(OCSP_Global.monitor); |
| 6145 |
| 6146 return SECSuccess; |
| 6147 } |
| 5788 | 6148 |
| 5789 SECStatus | 6149 SECStatus |
| 5790 CERT_GetOCSPResponseStatus(CERTOCSPResponse *response) | 6150 CERT_GetOCSPResponseStatus(CERTOCSPResponse *response) |
| 5791 { | 6151 { |
| 5792 PORT_Assert(response); | 6152 PORT_Assert(response); |
| 5793 if (response->statusValue == ocspResponse_successful) | 6153 if (response->statusValue == ocspResponse_successful) |
| 5794 return SECSuccess; | 6154 return SECSuccess; |
| 5795 | 6155 |
| 5796 switch (response->statusValue) { | 6156 switch (response->statusValue) { |
| 5797 case ocspResponse_malformedRequest: | 6157 case ocspResponse_malformedRequest: |
| (...skipping 12 matching lines...) Expand all Loading... |
| 5810 case ocspResponse_unauthorized: | 6170 case ocspResponse_unauthorized: |
| 5811 PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST); | 6171 PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST); |
| 5812 break; | 6172 break; |
| 5813 case ocspResponse_unused: | 6173 case ocspResponse_unused: |
| 5814 default: | 6174 default: |
| 5815 PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS); | 6175 PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS); |
| 5816 break; | 6176 break; |
| 5817 } | 6177 } |
| 5818 return SECFailure; | 6178 return SECFailure; |
| 5819 } | 6179 } |
| OLD | NEW |