private static unsafe partial int CryptoNative_X509DecodeOcspToExpiration( byte *buf, int len, SafeOcspRequestHandle req, IntPtr subject, IntPtr issuer, ref long expiration);
internal static SafeOcspRequestHandle X509ChainBuildOcspRequest(SafeX509StoreCtxHandle storeCtx, int chainDepth) { SafeOcspRequestHandle req = CryptoNative_X509ChainBuildOcspRequest(storeCtx, chainDepth); if (req.IsInvalid) { req.Dispose(); throw CreateOpenSslCryptographicException(); } return(req); }
internal static X509VerifyStatusCode X509ChainVerifyOcsp( SafeX509StoreCtxHandle ctx, SafeOcspRequestHandle req, SafeOcspResponseHandle resp, string cachePath) { X509VerifyStatusCode response = CryptoNative_X509ChainVerifyOcsp(ctx, req, resp, cachePath); if (response < 0) { Debug.Fail($"Unexpected response from X509ChainGetCachedOcspSuccess: {response}"); throw new CryptographicException(); } return(response); }
internal static unsafe bool X509DecodeOcspToExpiration( ReadOnlySpan <byte> buf, SafeOcspRequestHandle request, IntPtr x509Subject, IntPtr x509Issuer, out DateTimeOffset expiration) { long timeT = 0; int ret; fixed(byte *pBuf = buf) { ret = CryptoNative_X509DecodeOcspToExpiration( pBuf, buf.Length, request, x509Subject, x509Issuer, ref timeT); } if (ret == 1) { if (timeT != 0) { expiration = DateTimeOffset.FromUnixTimeSeconds(timeT); } else { // Something went wrong during the determination of when the response // should not be used any longer. // Half an hour sounds fair? expiration = DateTimeOffset.UtcNow.AddMinutes(30); } return(true); } Debug.Assert(ret == 0, $"Unexpected response from X509DecodeOcspToExpiration: {ret}"); expiration = DateTimeOffset.MinValue; return(false); }
private static partial int CryptoNative_X509ChainVerifyOcsp( SafeX509StoreCtxHandle ctx, SafeOcspRequestHandle req, SafeOcspResponseHandle resp, string cachePath, int chainDepth);
internal static partial int EncodeOcspRequest(SafeOcspRequestHandle req, byte[] buf);
internal static partial int GetOcspRequestDerSize(SafeOcspRequestHandle req);
private static extern X509VerifyStatusCode CryptoNative_X509ChainVerifyOcsp( SafeX509StoreCtxHandle ctx, SafeOcspRequestHandle req, SafeOcspResponseHandle resp, string cachePath, int chainDepth);
internal static extern int EncodeOcspRequest(SafeOcspRequestHandle req, byte[] buf);
internal static extern int GetOcspRequestDerSize(SafeOcspRequestHandle req);
private async Task <byte[]?> FetchOcspAsync() { X509Certificate2?caCert = _ca; Debug.Assert(_ocspUrls is not null); Debug.Assert(_ocspUrls.Count > 0); Debug.Assert(caCert is not null); IntPtr subject = Certificate.Handle; IntPtr issuer = caCert.Handle; using (SafeOcspRequestHandle ocspRequest = Interop.Crypto.X509BuildOcspRequest(subject, issuer)) { byte[] rentedBytes = ArrayPool <byte> .Shared.Rent(Interop.Crypto.GetOcspRequestDerSize(ocspRequest)); int encodingSize = Interop.Crypto.EncodeOcspRequest(ocspRequest, rentedBytes); ArraySegment <byte> encoded = new ArraySegment <byte>(rentedBytes, 0, encodingSize); ArraySegment <char> rentedChars = UrlBase64Encoding.RentEncode(encoded); byte[]? ret = null; for (int i = 0; i < _ocspUrls.Count; i++) { string url = MakeUrl(_ocspUrls[i], rentedChars); ret = await System.Net.Http.X509ResourceClient.DownloadAssetAsync(url, TimeSpan.MaxValue).ConfigureAwait(false); if (ret is not null) { if (!Interop.Crypto.X509DecodeOcspToExpiration(ret, ocspRequest, subject, issuer, out DateTimeOffset expiration)) { continue; } // Swap the working URL in as the first one we'll try next time. if (i != 0) { string tmp = _ocspUrls[0]; _ocspUrls[0] = _ocspUrls[i]; _ocspUrls[i] = tmp; } DateTimeOffset nextCheckA = DateTimeOffset.UtcNow.AddDays(1); DateTimeOffset nextCheckB = expiration.AddMinutes(-5); _ocspResponse = ret; _ocspExpiration = expiration; _nextDownload = nextCheckA < nextCheckB ? nextCheckA : nextCheckB; _pendingDownload = null; break; } } ArrayPool <byte> .Shared.Return(rentedBytes); ArrayPool <char> .Shared.Return(rentedChars.Array !); GC.KeepAlive(Certificate); GC.KeepAlive(caCert); return(ret); } }