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 |