C# .NET port of,
Install-Package Cats.CertificateTransparencyWarning
By default, this library uses the Certificate Transparency log list published by Google for Chrome:
https://www.gstatic.com/ct/log_list/v3/
This is not recommended for production use.
Google's CT log list endpoints are intended to support Chrome and are subject to Google's Acceptable Use Policy. Google explicitly states that third-party CT enforcement libraries relying on these endpoints may break.
Google can change the endpoint, format, schema, or availability of the log list at any time. Google is also actively fingerprinting and restricting third-party access.
As a result, applications using the default Google log list may stop working without any change to this library or the application. This has already occurred for Android clients using a mobile User-Agent, and further breakage is likely.
For production applications, you should ideally maintain and host your own CT log list rather than depending on Google's Chrome-specific infrastructure. This gives you control over the list, endpoint, schema and availability.
If you continue to use Google's log list, treat it as an external dependency that Google can change or break at any time.
The library is designed to be dependency-injection friendly; every service class has a matching interface. However, to get things running quickly, there is also a static Instance class which constructs lazy singletons for both ILogListService and CertificateTransparencyVerifier.
If you want to provide a custom list of included and excluded domains to these static instances, call Instance.InitDomains first. By default, validation is enabled for all TLS-secured domains.
Instance.InitDomains(new [] { "*.google.com", "microsoft.com" }, new [] { "nuget.org" });var client = new HttpClient(new HttpClientHandler()
{
ServerCertificateCustomValidationCallback = (request, certificate, chain, sslPolicyErrors) =>
{
var certificateChain = chain.ChainElements.OfType<X509ChainElement>().Select(i => i.Certificate).ToList();
var certificateVerifier = Cats.CertificateTransparency.Instance.CertificateTransparencyVerifier;
var ctValueTask = certificateVerifier.IsValidAsync(request.RequestUri.Host, certificateChain, CancellationToken.None);
var ctResult = ctValueTask.IsCompleted
? ctValueTask.Result
: ctValueTask.AsTask().Result;
return ctResult.IsValid;
}
});Important
Android 16+ (API 36) should use the native Android Certificate Transparency implementation instead of this library.
See Android's native CT enforcement and the default Android CT policy.
For applications targeting Android versions prior to Android 16, the Android implementation can be used:
bool VerifyCtResult(string hostname, IList<DotNetX509Certificate> certificateChain, CtVerificationResult result)
{
// Fail open if the CT log list is unreachable.
if (result == CtResult.LogServersFailed)
{
return true;
}
// Add any additional checks or logging here.
return result.IsValid;
}
var httpHandler = new Cats.CertificateTransparency.CatsAndroidClientHandler(VerifyCtResult);
var client = new HttpClient(httpHandler);There is currently no platform specific implementation for iOS. Certificate transparency is already enabled since iOS 12.1.1, however, it can be disabled per domain via a property list setting NSRequiresCertificateTransparency.
If you are keen you could use the CertificateVerifier to build your own HttpClientHandler, similar to the included Android implementation.
A CT log list contains the Certificate Transparency logs that are trusted for verification.
For production applications, maintaining your own log list is recommended. Your application then controls:
- Which CT logs are trusted.
- Where the log list is hosted.
- The availability of the log list.
- Updates to the log list.
- The format and schema used by your application.
Using Google's Chrome log list is convenient but creates a dependency on infrastructure that is outside the control of this project. Google may change or restrict access to the list without notice, and applications should expect the Chrome log list to break eventually.
If you maintain your own log list, configure the library to use it through the appropriate ILogListService implementation.
Any contributions are welcome! Especially extra test cases!
