private static string?GetCdpUrl(SafeX509Handle cert) { ArraySegment <byte> crlDistributionPoints = OpenSslX509CertificateReader.FindFirstExtension(cert, Oids.CrlDistributionPoints); if (crlDistributionPoints.Array == null) { return(null); } try { AsnValueReader reader = new AsnValueReader(crlDistributionPoints, AsnEncodingRules.DER); AsnValueReader sequenceReader = reader.ReadSequence(); reader.ThrowIfNotEmpty(); while (sequenceReader.HasData) { DistributionPointAsn.Decode(ref sequenceReader, crlDistributionPoints, out DistributionPointAsn distributionPoint); // Only distributionPoint is supported // Only fullName is supported, nameRelativeToCRLIssuer is for LDAP-based lookup. if (distributionPoint.DistributionPoint.HasValue && distributionPoint.DistributionPoint.Value.FullName != null) { foreach (GeneralNameAsn name in distributionPoint.DistributionPoint.Value.FullName) { if (name.Uri != null && Uri.TryCreate(name.Uri, UriKind.Absolute, out Uri? uri) && uri.Scheme == "http") { return(name.Uri); } } } } } catch (CryptographicException) { // Treat any ASN errors as if the extension was missing. } catch (AsnContentException) { // Treat any ASN errors as if the extension was missing. } finally { // The data came from a certificate, so it's public. CryptoPool.Return(crlDistributionPoints.Array, clearSize: 0); } return(null); }
private static string GetCdpUrl(SafeX509Handle cert) { ArraySegment <byte> crlDistributionPoints = OpenSslX509CertificateReader.FindFirstExtension(cert, Oids.CrlDistributionPoints); if (crlDistributionPoints.Array == null) { return(null); } try { AsnReader reader = new AsnReader(crlDistributionPoints, AsnEncodingRules.DER); AsnReader sequenceReader = reader.ReadSequence(); reader.ThrowIfNotEmpty(); while (sequenceReader.HasData) { DistributionPointAsn.Decode(sequenceReader, out DistributionPointAsn distributionPoint); // Only distributionPoint is supported // Only fullName is supported, nameRelativeToCRLIssuer is for LDAP-based lookup. if (distributionPoint.DistributionPoint.HasValue && distributionPoint.DistributionPoint.Value.FullName != null) { foreach (GeneralNameAsn name in distributionPoint.DistributionPoint.Value.FullName) { if (name.Uri != null && Uri.TryCreate(name.Uri, UriKind.Absolute, out Uri uri) && uri.Scheme == "http") { return(name.Uri); } } } } return(null); } finally { ArrayPool <byte> .Shared.Return(crlDistributionPoints.Array); } }
internal Interop.Crypto.X509VerifyStatusCode FindChainViaAia( ref List <X509Certificate2> downloadedCerts) { IntPtr lastCert = IntPtr.Zero; SafeX509StoreCtxHandle storeCtx = _storeCtx; Interop.Crypto.X509VerifyStatusCode statusCode = Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT; while (!IsCompleteChain(statusCode)) { using (SafeX509Handle currentCert = Interop.Crypto.X509StoreCtxGetCurrentCert(storeCtx)) { IntPtr currentHandle = currentCert.DangerousGetHandle(); // No progress was made, give up. if (currentHandle == lastCert) { break; } lastCert = currentHandle; ArraySegment <byte> authorityInformationAccess = OpenSslX509CertificateReader.FindFirstExtension( currentCert, Oids.AuthorityInformationAccess); if (authorityInformationAccess.Count == 0) { break; } X509Certificate2 downloaded = DownloadCertificate( authorityInformationAccess, ref _remainingDownloadTime); // The AIA record is contained in a public structure, so no need to clear it. CryptoPool.Return(authorityInformationAccess.Array, clearSize: 0); if (downloaded == null) { break; } if (downloadedCerts == null) { downloadedCerts = new List <X509Certificate2>(); } AddToStackAndUpRef(downloaded.Handle, _untrustedLookup); downloadedCerts.Add(downloaded); Interop.Crypto.X509StoreCtxRebuildChain(storeCtx); statusCode = Interop.Crypto.X509StoreCtxGetError(storeCtx); } } if (statusCode == Interop.Crypto.X509VerifyStatusCode.X509_V_OK && downloadedCerts != null) { using (SafeX509StackHandle chainStack = Interop.Crypto.X509StoreCtxGetChain(_storeCtx)) { int chainSize = Interop.Crypto.GetX509StackFieldCount(chainStack); Span <IntPtr> tempChain = stackalloc IntPtr[DefaultChainCapacity]; byte[] tempChainRent = null; if (chainSize <= tempChain.Length) { tempChain = tempChain.Slice(0, chainSize); } else { int targetSize = checked (chainSize * IntPtr.Size); tempChainRent = CryptoPool.Rent(targetSize); tempChain = MemoryMarshal.Cast <byte, IntPtr>(tempChainRent.AsSpan(0, targetSize)); } for (int i = 0; i < chainSize; i++) { tempChain[i] = Interop.Crypto.GetX509StackField(chainStack, i); } // In the average case we never made it here. // // Given that we made it here, in the average remaining case // we are doing a one item for which will match in the second position // of an (on-average) 3 item collection. // // The only case where this loop really matters is if downloading the // certificate made an alternate chain better, which may have resulted in // an extra download and made the first one not be involved any longer. In // that case, it's a 2 item for loop matching against a three item set. // // So N*M is well contained. for (int i = downloadedCerts.Count - 1; i >= 0; i--) { X509Certificate2 downloadedCert = downloadedCerts[i]; if (!tempChain.Contains(downloadedCert.Handle)) { downloadedCert.Dispose(); downloadedCerts.RemoveAt(i); } } if (downloadedCerts.Count == 0) { downloadedCerts = null; } if (tempChainRent != null) { CryptoPool.Return(tempChainRent); } } } return(statusCode); }