未验证 提交 57da7d22 编写于 作者: J Jeremy Barton 提交者: GitHub

Use the stapled OCSP response from TLS on Linux, when available

Based on (non-exhaustive) testing, chain builds from a Let's Encrypt issued certificate have
the following characteristics:

* Live OCSP request required (uncached/unstapled): 577ms
* OCSP response retrieved from cache (unstapled): 183ms
* OCSP response utilized from TLS stapling (bypasses cache): 182ms

In both cached and stapled the revocation portion was about 39ms.
(The revocation mode was ExcludeRoot, the CRL pertaining to the intermediate was cached for all three measurements.)

If the OCSP response was stapled (and the math worked out OK on it) then we completely ignore the OCSP cache.
While it could potentially be useful to update the cache if the stapled response was newer, the extra I/O of doing
the "newer" test didn't feel justified at this time.
上级 6410312a
......@@ -53,6 +53,22 @@ internal static X509VerifyStatusCode X509ChainGetCachedOcspStatus(SafeX509StoreC
return response;
}
[LibraryImport(Libraries.CryptoNative)]
private static partial int CryptoNative_X509ChainHasStapledOcsp(SafeX509StoreCtxHandle storeCtx);
internal static bool X509ChainHasStapledOcsp(SafeX509StoreCtxHandle storeCtx)
{
int resp = CryptoNative_X509ChainHasStapledOcsp(storeCtx);
if (resp == 1)
{
return true;
}
Debug.Assert(resp == 0, $"Unexpected response from X509ChainHasStapledOcsp: {resp}");
return false;
}
[LibraryImport(Libraries.CryptoNative, StringMarshalling = StringMarshalling.Utf8)]
private static partial int CryptoNative_X509ChainVerifyOcsp(
SafeX509StoreCtxHandle ctx,
......
......@@ -59,6 +59,7 @@ internal sealed class OpenSslX509ChainEventSource : EventSource
private const int EventId_RevocationCheckStart = 45;
private const int EventId_RevocationCheckStop = 46;
private const int EventId_CrlIdentifiersDetermined = 47;
private const int EventId_StapledOcspPresent = 48;
private static string GetCertificateSubject(SafeX509Handle certHandle)
{
......@@ -745,5 +746,17 @@ private void CrlIdentifiersDetermined(string subjectName, string crlDistribution
{
WriteEvent(EventId_CrlIdentifiersDetermined, subjectName, crlDistributionPoint, cacheFileName);
}
[Event(
EventId_StapledOcspPresent,
Level = EventLevel.Verbose,
Message = "The target certificate has a stapled OCSP request, skipping the CRL check.")]
internal void StapledOcspPresent()
{
if (IsEnabled())
{
WriteEvent(EventId_StapledOcspPresent);
}
}
}
}
......@@ -388,15 +388,25 @@ internal static void FlushStores()
{
for (int i = 0; i < revocationSize; i++)
{
using (SafeX509Handle cert =
Interop.Crypto.X509UpRef(Interop.Crypto.GetX509StackField(chainStack, i)))
if (i == 0 && Interop.Crypto.X509ChainHasStapledOcsp(_storeCtx))
{
OpenSslCrlCache.AddCrlForCertificate(
cert,
_store,
revocationMode,
_verificationTime,
_downloadTimeout);
if (OpenSslX509ChainEventSource.Log.IsEnabled())
{
OpenSslX509ChainEventSource.Log.StapledOcspPresent();
}
}
else
{
using (SafeX509Handle cert =
Interop.Crypto.X509UpRef(Interop.Crypto.GetX509StackField(chainStack, i)))
{
OpenSslCrlCache.AddCrlForCertificate(
cert,
_store,
revocationMode,
_verificationTime,
_downloadTimeout);
}
}
}
}
......
......@@ -236,6 +236,7 @@ static const Entry s_cryptoNative[] =
DllImportEntry(CryptoNative_UpRefEvpPkey)
DllImportEntry(CryptoNative_X509ChainBuildOcspRequest)
DllImportEntry(CryptoNative_X509ChainGetCachedOcspStatus)
DllImportEntry(CryptoNative_X509ChainHasStapledOcsp)
DllImportEntry(CryptoNative_X509ChainNew)
DllImportEntry(CryptoNative_X509ChainVerifyOcsp)
DllImportEntry(CryptoNative_X509CheckPurpose)
......
......@@ -5,6 +5,7 @@
#include "pal_types.h"
#include "pal_utilities.h"
#include "pal_safecrt.h"
#include "pal_x509.h"
#include "openssl.h"
#ifdef FEATURE_DISTRO_AGNOSTIC_SSL
......@@ -19,6 +20,12 @@
#include <time.h>
#include <unistd.h>
#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_0_RTM
c_static_assert(CRYPTO_EX_INDEX_X509 == 3);
#else
c_static_assert(CRYPTO_EX_INDEX_X509 == 10);
#endif
// See X509NameType.SimpleName
#define NAME_TYPE_SIMPLE 0
// See X509NameType.EmailName
......@@ -1172,6 +1179,70 @@ int64_t CryptoNative_OpenSslVersionNumber()
return (int64_t)OpenSSL_version_num();
}
static void ExDataFree(
void* parent,
void* ptr,
CRYPTO_EX_DATA* ad,
int idx,
long argl,
void* argp)
{
(void)parent;
(void)ad;
(void)idx;
(void)argl;
(void)argp;
if (ptr != NULL)
{
if (idx == g_x509_ocsp_index)
{
OCSP_RESPONSE_free((OCSP_RESPONSE*)ptr);
}
}
}
// In the OpenSSL 1.0.2 headers, the `from` argument is not const (became const in 1.1.0)
// In the OpenSSL 3 headers, `from_d` changed from (void*) to (void**).
static int ExDataDup(
CRYPTO_EX_DATA* to,
#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_0_RTM
const CRYPTO_EX_DATA* from,
#else
CRYPTO_EX_DATA* from,
#endif
#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_3_0_RTM
void** from_d,
#else
void* from_d,
#endif
int idx,
long argl,
void* argp)
{
(void)to;
(void)from;
(void)idx;
(void)argl;
(void)argp;
// From the docs (https://www.openssl.org/docs/man1.1.1/man3/CRYPTO_get_ex_new_index.html):
// "The from_d parameter needs to be cast to a void **pptr as the API has currently the wrong signature ..."
void** pptr = (void**)from_d;
if (pptr != NULL)
{
if (idx == g_x509_ocsp_index)
{
*pptr = NULL;
}
}
// If the dup_func() returns 0 the whole CRYPTO_dup_ex_data() will fail.
// So, return 1 unless we returned 0 already.
return 1;
}
void CryptoNative_RegisterLegacyAlgorithms()
{
#ifdef NEED_OPENSSL_3_0
......@@ -1304,6 +1375,9 @@ static int32_t EnsureOpenSsl10Initialized()
// Ensure that the error message table is loaded.
ERR_load_crypto_strings();
// In OpenSSL 1.0.2-, CRYPTO_EX_INDEX_X509 is 10.
g_x509_ocsp_index = CRYPTO_get_ex_new_index(10, 0, NULL, NULL, ExDataDup, ExDataFree);
done:
if (ret != 0)
{
......@@ -1368,6 +1442,9 @@ static int32_t EnsureOpenSsl11Initialized()
// atexit handler, so we will indicate that we're in the shutdown state
// and stop asking problematic questions from other threads.
atexit(HandleShutdown);
// In OpenSSL 1.1.0+, CRYPTO_EX_INDEX_X509 is 3.
g_x509_ocsp_index = CRYPTO_get_ex_new_index(3, 0, NULL, NULL, ExDataDup, ExDataFree);
return 0;
}
......@@ -1385,9 +1462,12 @@ int32_t CryptoNative_OpenSslAvailable()
}
static int32_t g_initStatus = 1;
int g_x509_ocsp_index = -1;
static int32_t EnsureOpenSslInitializedCore()
{
int ret = 0;
// If portable then decide which OpenSSL we are, and call the right one.
// If 1.0, call the 1.0 one.
// Otherwise call the 1.1 one.
......@@ -1396,17 +1476,26 @@ static int32_t EnsureOpenSslInitializedCore()
if (API_EXISTS(SSL_state))
{
return EnsureOpenSsl10Initialized();
ret = EnsureOpenSsl10Initialized();
}
else
{
return EnsureOpenSsl11Initialized();
ret = EnsureOpenSsl11Initialized();
}
#elif OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0_RTM
return EnsureOpenSsl10Initialized();
ret = EnsureOpenSsl10Initialized();
#else
return EnsureOpenSsl11Initialized();
ret = EnsureOpenSsl11Initialized();
#endif
if (ret == 0)
{
// On OpenSSL 1.0.2 our expected index is 0.
// On OpenSSL 1.1.0+ 0 is a reserved value and we expect 1.
assert(g_x509_ocsp_index != -1);
}
return ret;
}
static void EnsureOpenSslInitializedOnce()
......
......@@ -195,6 +195,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void);
REQUIRED_FUNCTION(BN_num_bits) \
REQUIRED_FUNCTION(BN_set_word) \
LEGACY_FUNCTION(CRYPTO_add_lock) \
REQUIRED_FUNCTION(CRYPTO_get_ex_new_index) \
LEGACY_FUNCTION(CRYPTO_num_locks) \
LEGACY_FUNCTION(CRYPTO_set_locking_callback) \
REQUIRED_FUNCTION(d2i_ASN1_BIT_STRING) \
......@@ -548,6 +549,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void);
REQUIRED_FUNCTION(X509_get_default_cert_dir_env) \
REQUIRED_FUNCTION(X509_get_default_cert_file) \
REQUIRED_FUNCTION(X509_get_default_cert_file_env) \
REQUIRED_FUNCTION(X509_get_ex_data) \
REQUIRED_FUNCTION(X509_get_ext) \
REQUIRED_FUNCTION(X509_get_ext_by_NID) \
REQUIRED_FUNCTION(X509_get_ext_count) \
......@@ -575,6 +577,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void);
REQUIRED_FUNCTION(X509_new) \
REQUIRED_FUNCTION(X509_PUBKEY_get) \
FALLBACK_FUNCTION(X509_PUBKEY_get0_param) \
REQUIRED_FUNCTION(X509_set_ex_data) \
REQUIRED_FUNCTION(X509_set_pubkey) \
REQUIRED_FUNCTION(X509_sign) \
REQUIRED_FUNCTION(X509_subject_name_hash) \
......@@ -666,6 +669,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define BN_num_bits BN_num_bits_ptr
#define BN_set_word BN_set_word_ptr
#define CRYPTO_add_lock CRYPTO_add_lock_ptr
#define CRYPTO_get_ex_new_index CRYPTO_get_ex_new_index_ptr
#define CRYPTO_num_locks CRYPTO_num_locks_ptr
#define CRYPTO_set_locking_callback CRYPTO_set_locking_callback_ptr
#define d2i_ASN1_BIT_STRING d2i_ASN1_BIT_STRING_ptr
......@@ -1028,6 +1032,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define X509_get_default_cert_dir_env X509_get_default_cert_dir_env_ptr
#define X509_get_default_cert_file X509_get_default_cert_file_ptr
#define X509_get_default_cert_file_env X509_get_default_cert_file_env_ptr
#define X509_get_ex_data X509_get_ex_data_ptr
#define X509_get_ext X509_get_ext_ptr
#define X509_get_ext_by_NID X509_get_ext_by_NID_ptr
#define X509_get_ext_count X509_get_ext_count_ptr
......@@ -1049,6 +1054,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define X509_new X509_new_ptr
#define X509_PUBKEY_get0_param X509_PUBKEY_get0_param_ptr
#define X509_PUBKEY_get X509_PUBKEY_get_ptr
#define X509_set_ex_data X509_set_ex_data_ptr
#define X509_set_pubkey X509_set_pubkey_ptr
#define X509_subject_name_hash X509_subject_name_hash_ptr
#define X509_sign X509_sign_ptr
......
......@@ -17,6 +17,8 @@ c_static_assert(PAL_SSL_ERROR_WANT_READ == SSL_ERROR_WANT_READ);
c_static_assert(PAL_SSL_ERROR_WANT_WRITE == SSL_ERROR_WANT_WRITE);
c_static_assert(PAL_SSL_ERROR_SYSCALL == SSL_ERROR_SYSCALL);
c_static_assert(PAL_SSL_ERROR_ZERO_RETURN == SSL_ERROR_ZERO_RETURN);
c_static_assert(SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE == 65);
c_static_assert(TLSEXT_STATUSTYPE_ocsp == 1);
#define DOTNET_DEFAULT_CIPHERSTRING \
"ECDHE-ECDSA-AES256-GCM-SHA384:" \
......@@ -234,6 +236,12 @@ SSL_CTX* CryptoNative_SslCtxCreate(const SSL_METHOD* method)
return NULL;
}
}
// Opportunistically request the server present a stapled OCSP response.
if (SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE, TLSEXT_STATUSTYPE_ocsp, NULL) != 1)
{
ERR_clear_error();
}
}
return ctx;
......@@ -559,8 +567,26 @@ int32_t CryptoNative_IsSslStateOK(SSL* ssl)
X509* CryptoNative_SslGetPeerCertificate(SSL* ssl)
{
const uint8_t* data = NULL;
long len = SSL_get_tlsext_status_ocsp_resp(ssl, &data);
X509* cert = SSL_get1_peer_certificate(ssl);
if (len > 0 && cert != NULL)
{
OCSP_RESPONSE* ocspResp = d2i_OCSP_RESPONSE(NULL, &data, len);
if (ocspResp == NULL)
{
ERR_clear_error();
}
else
{
X509_set_ex_data(cert, g_x509_ocsp_index, ocspResp);
}
}
// No error queue impact.
return SSL_get1_peer_certificate(ssl);
return cert;
}
X509Stack* CryptoNative_SslGetPeerCertChain(SSL* ssl)
......
......@@ -871,27 +871,29 @@ static OCSP_CERTID* MakeCertId(X509* subject, X509* issuer)
return OCSP_cert_to_id(EVP_sha1(), subject, issuer);
}
static time_t GetIssuanceWindowStart()
{
// time_t granularity is seconds, so subtract 4 days worth of seconds.
// The 4 day policy is based on the CA/Browser Forum Baseline Requirements
// (version 1.6.3) section 4.9.10 (On-Line Revocation Checking Requirements)
time_t t = time(NULL);
t -= 4 * 24 * 60 * 60;
return t;
}
static X509VerifyStatusCode CheckOcsp(OCSP_REQUEST* req,
OCSP_RESPONSE* resp,
X509* subject,
X509* issuer,
X509_STORE_CTX* storeCtx,
ASN1_GENERALIZEDTIME** thisUpdate,
ASN1_GENERALIZEDTIME** nextUpdate)
int* canCache)
{
if (thisUpdate != NULL)
{
*thisUpdate = NULL;
}
if (nextUpdate != NULL)
{
*nextUpdate = NULL;
}
assert(resp != NULL);
assert(subject != NULL);
assert(issuer != NULL);
assert(canCache != NULL);
*canCache = 0;
OCSP_CERTID* certId = MakeCertId(subject, issuer);
......@@ -935,23 +937,49 @@ static X509VerifyStatusCode CheckOcsp(OCSP_REQUEST* req,
if (OCSP_resp_find_status(basicResp, certId, &status, NULL, NULL, &thisupd, &nextupd))
{
if (thisUpdate != NULL && thisupd != NULL)
{
*thisUpdate = ASN1_STRING_dup(thisupd);
}
// X509_cmp_current_time uses 0 for error already, so we can use it when there's a null value.
// 1 means the nextupd value is in the future, -1 means it is now-or-in-the-past.
// Following with OpenSSL conventions, we'll accept "now" as "the past".
int nextUpdComparison = nextupd == NULL ? 0 : X509_cmp_current_time(nextupd);
if (nextUpdate != NULL && nextupd != NULL)
// Un-revoking is rare, so reporting revoked on an expired response has a low chance
// of a false-positive.
//
// For non-revoked responses, a next-update value in the past counts as expired.
if (status == V_OCSP_CERTSTATUS_REVOKED)
{
*nextUpdate = ASN1_STRING_dup(nextupd);
ret = PAL_X509_V_ERR_CERT_REVOKED;
}
if (status == V_OCSP_CERTSTATUS_GOOD)
else
{
ret = PAL_X509_V_OK;
if (nextupd != NULL && nextUpdComparison <= 0)
{
ret = PAL_X509_V_ERR_CRL_HAS_EXPIRED;
}
else if (status == V_OCSP_CERTSTATUS_GOOD)
{
ret = PAL_X509_V_OK;
}
}
else if (status == V_OCSP_CERTSTATUS_REVOKED)
// We can cache if (all of):
// * We have a definitive answer
// * We have a this-update value
// * The this-update value is not too old (see GetIssuanceWindowStart)
// * We have a next-update value
// * The next-update value is in the future
//
// It is up to the caller to decide what, if anything, to do with this information.
if (ret != PAL_X509_V_ERR_UNABLE_TO_GET_CRL &&
thisupd != NULL &&
nextUpdComparison > 0)
{
ret = PAL_X509_V_ERR_CERT_REVOKED;
time_t oldest = GetIssuanceWindowStart();
if (X509_cmp_time(thisupd, &oldest) > 0)
{
*canCache = 1;
}
}
}
}
......@@ -987,14 +1015,17 @@ static int Get0CertAndIssuer(X509_STORE_CTX* storeCtx, int chainDepth, X509** su
return 1;
}
static time_t GetIssuanceWindowStart()
static X509VerifyStatusCode GetStapledOcspStatus(X509_STORE_CTX* storeCtx, X509* subject, X509* issuer)
{
// time_t granularity is seconds, so subtract 4 days worth of seconds.
// The 4 day policy is based on the CA/Browser Forum Baseline Requirements
// (version 1.6.3) section 4.9.10 (On-Line Revocation Checking Requirements)
time_t t = time(NULL);
t -= 4 * 24 * 60 * 60;
return t;
OCSP_RESPONSE* ocspResp = (OCSP_RESPONSE*)X509_get_ex_data(subject, g_x509_ocsp_index);
if (ocspResp == NULL)
{
return PAL_X509_V_ERR_UNABLE_TO_GET_CRL;
}
int canCache = 0;
return CheckOcsp(NULL, ocspResp, subject, issuer, storeCtx, &canCache);
}
int32_t CryptoNative_X509ChainGetCachedOcspStatus(X509_STORE_CTX* storeCtx, char* cachePath, int chainDepth)
......@@ -1014,6 +1045,16 @@ int32_t CryptoNative_X509ChainGetCachedOcspStatus(X509_STORE_CTX* storeCtx, char
return -2;
}
if (chainDepth == 0)
{
X509VerifyStatusCode stapledRet = GetStapledOcspStatus(storeCtx, subject, issuer);
if (stapledRet == PAL_X509_V_OK || stapledRet == PAL_X509_V_ERR_CERT_REVOKED)
{
return (int32_t)stapledRet;
}
}
X509VerifyStatusCode ret = PAL_X509_V_ERR_UNABLE_TO_GET_CRL;
char* fullPath = BuildOcspCacheFilename(cachePath, subject);
......@@ -1033,35 +1074,14 @@ int32_t CryptoNative_X509ChainGetCachedOcspStatus(X509_STORE_CTX* storeCtx, char
if (resp != NULL)
{
ASN1_GENERALIZEDTIME* thisUpdate = NULL;
ASN1_GENERALIZEDTIME* nextUpdate = NULL;
ret = CheckOcsp(NULL, resp, subject, issuer, storeCtx, &thisUpdate, &nextUpdate);
int canCache = 0;
ret = CheckOcsp(NULL, resp, subject, issuer, storeCtx, &canCache);
if (ret != PAL_X509_V_ERR_UNABLE_TO_GET_CRL)
if (!canCache)
{
time_t oldest = GetIssuanceWindowStart();
// If either the thisUpdate or nextUpdate is missing we can't determine policy, so reject it.
// oldest = now - window;
//
// if thisUpdate < oldest || nextUpdate < now, reject.
//
// Since X509_cmp(_current)_time returns 0 on error, do a <= 0 check.
if (nextUpdate == NULL || thisUpdate == NULL || X509_cmp_current_time(nextUpdate) <= 0 ||
X509_cmp_time(thisUpdate, &oldest) <= 0)
{
ret = PAL_X509_V_ERR_UNABLE_TO_GET_CRL;
}
}
if (nextUpdate != NULL)
{
ASN1_GENERALIZEDTIME_free(nextUpdate);
}
if (thisUpdate != NULL)
{
ASN1_GENERALIZEDTIME_free(thisUpdate);
// If the response wasn't suitable for caching, treat it as PAL_X509_V_ERR_UNABLE_TO_GET_CRL,
// which will cause us to delete the cache entry and move on to a live request.
ret = PAL_X509_V_ERR_UNABLE_TO_GET_CRL;
}
}
......@@ -1131,24 +1151,8 @@ OCSP_REQUEST* CryptoNative_X509ChainBuildOcspRequest(X509_STORE_CTX* storeCtx, i
return req;
}
int32_t
CryptoNative_X509ChainVerifyOcsp(X509_STORE_CTX* storeCtx, OCSP_REQUEST* req, OCSP_RESPONSE* resp, char* cachePath, int chainDepth)
static int32_t X509ChainVerifyOcsp(X509_STORE_CTX* storeCtx, X509* subject, X509* issuer, OCSP_REQUEST* req, OCSP_RESPONSE* resp, char* cachePath)
{
if (storeCtx == NULL || req == NULL || resp == NULL)
{
return -1;
}
ERR_clear_error();
X509* subject;
X509* issuer;
if (!Get0CertAndIssuer(storeCtx, chainDepth, &subject, &issuer))
{
return -2;
}
X509VerifyStatusCode ret = PAL_X509_V_ERR_UNABLE_TO_GET_CRL;
OCSP_CERTID* certId = MakeCertId(subject, issuer);
......@@ -1157,69 +1161,79 @@ CryptoNative_X509ChainVerifyOcsp(X509_STORE_CTX* storeCtx, OCSP_REQUEST* req, OC
return -3;
}
ASN1_GENERALIZEDTIME* thisUpdate = NULL;
ASN1_GENERALIZEDTIME* nextUpdate = NULL;
ret = CheckOcsp(req, resp, subject, issuer, storeCtx, &thisUpdate, &nextUpdate);
int canCache = 0;
ret = CheckOcsp(req, resp, subject, issuer, storeCtx, &canCache);
if (ret == PAL_X509_V_OK || ret == PAL_X509_V_ERR_CERT_REVOKED)
if (canCache)
{
// If the nextUpdate time is in the past (or corrupt), report either REVOKED or CRL_EXPIRED
if (nextUpdate != NULL && X509_cmp_current_time(nextUpdate) <= 0)
{
if (ret == PAL_X509_V_OK)
{
ret = PAL_X509_V_ERR_CRL_HAS_EXPIRED;
}
}
else
char* fullPath = BuildOcspCacheFilename(cachePath, subject);
if (fullPath != NULL)
{
time_t oldest = GetIssuanceWindowStart();
int clearErr = 1;
BIO* bio = BIO_new_file(fullPath, "wb");
// If the response is within our caching policy (which requires a nextUpdate value)
// then try to cache it.
if (nextUpdate != NULL && thisUpdate != NULL && X509_cmp_time(thisUpdate, &oldest) > 0)
if (bio != NULL)
{
char* fullPath = BuildOcspCacheFilename(cachePath, subject);
if (fullPath != NULL)
{
int clearErr = 1;
BIO* bio = BIO_new_file(fullPath, "wb");
if (bio != NULL)
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-qual"
if (i2d_OCSP_RESPONSE_bio(bio, resp))
if (i2d_OCSP_RESPONSE_bio(bio, resp))
#pragma clang diagnostic pop
{
clearErr = 0;
}
BIO_free(bio);
}
{
clearErr = 0;
}
if (clearErr)
{
ERR_clear_error();
unlink(fullPath);
}
BIO_free(bio);
}
free(fullPath);
}
if (clearErr)
{
ERR_clear_error();
unlink(fullPath);
}
free(fullPath);
}
}
if (nextUpdate != NULL)
return (int32_t)ret;
}
int32_t CryptoNative_X509ChainHasStapledOcsp(X509_STORE_CTX* storeCtx)
{
assert(storeCtx != NULL);
ERR_clear_error();
X509* subject;
X509* issuer;
if (!Get0CertAndIssuer(storeCtx, 0, &subject, &issuer))
{
return -2;
}
X509VerifyStatusCode status = GetStapledOcspStatus(storeCtx, subject, issuer);
return status == PAL_X509_V_OK || status == PAL_X509_V_ERR_CERT_REVOKED;
}
int32_t
CryptoNative_X509ChainVerifyOcsp(X509_STORE_CTX* storeCtx, OCSP_REQUEST* req, OCSP_RESPONSE* resp, char* cachePath, int chainDepth)
{
if (storeCtx == NULL || req == NULL || resp == NULL)
{
ASN1_GENERALIZEDTIME_free(nextUpdate);
return -1;
}
if (thisUpdate != NULL)
ERR_clear_error();
X509* subject;
X509* issuer;
if (!Get0CertAndIssuer(storeCtx, chainDepth, &subject, &issuer))
{
ASN1_GENERALIZEDTIME_free(thisUpdate);
return -2;
}
return (int32_t)ret;
return X509ChainVerifyOcsp(storeCtx, subject, issuer, req, resp, cachePath);
}
......@@ -5,6 +5,8 @@
#include "pal_compiler.h"
#include "pal_crypto_types.h"
extern int g_x509_ocsp_index;
/*
These values should be kept in sync with System.Security.Cryptography.X509Certificates.X509RevocationFlag.
*/
......@@ -381,6 +383,11 @@ determined by the chain in storeCtx.
*/
PALEXPORT OCSP_REQUEST* CryptoNative_X509ChainBuildOcspRequest(X509_STORE_CTX* storeCtx, int chainDepth);
/*
Checks if the target certificate has an appropriate stapled OCSP response.
*/
PALEXPORT int32_t CryptoNative_X509ChainHasStapledOcsp(X509_STORE_CTX* storeCtx);
/*
Determine if the OCSP response is acceptable, and if acceptable report the status and
cache the result (if appropriate)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册