Keywords: .NET Core | HttpClient | Client Certificate | Two-Way SSL Authentication | Kestrel Configuration
Abstract: This article provides a comprehensive guide on adding client certificates to HttpClient in .NET Core applications for two-way SSL authentication. It covers HttpClientHandler configuration, certificate store access, Kestrel server setup, and ASP.NET Core authentication middleware integration, offering end-to-end implementation from client requests to server validation with detailed code examples and configuration instructions.
Introduction
In modern distributed systems, two-way SSL authentication (also known as client certificate authentication) is a crucial mechanism for securing inter-service communication. Unlike traditional one-way SSL, two-way SSL requires both client and server to provide valid digital certificates, establishing a more secure communication channel. In the .NET Core ecosystem, HttpClient serves as the primary HTTP client component, and its client certificate configuration requires specific technical implementation.
HttpClient Client Certificate Configuration
In .NET Core, the core of adding client certificates to HttpClient lies in properly configuring HttpClientHandler. The following code demonstrates the basic configuration approach:
var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.SslProtocols = SslProtocols.Tls12;
handler.ClientCertificates.Add(new X509Certificate2("cert.crt"));
var client = new HttpClient(handler);Here, ClientCertificateOption.Manual indicates manual management of client certificates, and SslProtocols.Tls12 specifies the use of TLS 1.2 protocol, which aligns with modern security standards.
Certificate Store and Retrieval
In real production environments, certificates are typically stored in the system's certificate store rather than used directly from files. The following code shows how to retrieve a certificate from the local machine's root store:
public class CertificateHelper
{
protected internal static X509Certificate2 GetServiceCertificate(string subjectName)
{
using (var certStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
{
certStore.Open(OpenFlags.ReadOnly);
var certCollection = certStore.Certificates.Find(
X509FindType.FindBySubjectDistinguishedName, subjectName, true);
X509Certificate2 certificate = null;
if (certCollection.Count > 0)
{
certificate = certCollection[0];
}
return certificate;
}
}
}This method searches for matching certificates in the root store by subject distinguished name, ensuring the correct client certificate is obtained.
Application Startup Configuration
In ASP.NET Core applications, you need to configure the Kestrel server in the Program.Main method to support client certificate authentication:
var host = WebHost.CreateDefaultBuilder(args)
.ConfigureKestrel(options =>
{
options.Listen(new IPEndPoint(IPAddress.Loopback, 443), listenOptions =>
{
var httpsConnectionAdapterOptions = new HttpsConnectionAdapterOptions()
{
ClientCertificateMode = ClientCertificateMode.AllowCertificate,
SslProtocols = System.Security.Authentication.SslProtocols.Tls12,
ServerCertificate = certificate
};
listenOptions.UseHttps(httpsConnectionAdapterOptions);
});
})
.UseStartup<Startup>()
.Build();
host.Run();This configuration enables the Kestrel server to listen for HTTPS requests on port 443 and allows clients to provide certificates for authentication.
Authentication Middleware Configuration
Configure the certificate authentication middleware in Startup.cs to handle client certificate validation:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CertificateAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CertificateAuthenticationDefaults.AuthenticationScheme;
})
.AddCertificateAuthentication(certOptions =>
{
var certificateAndRoles = new List<CertficateAuthenticationOptions.CertificateAndRoles>();
Configuration.GetSection("AuthorizedCertficatesAndRoles:CertificateAndRoles").Bind(certificateAndRoles);
certOptions.CertificatesAndRoles = certificateAndRoles.ToArray();
});This setup designates certificate authentication as the default scheme and loads authorized certificates and roles from the configuration file.
Server-Side Certificate Validation
In controllers, you can validate client certificates as follows:
X509Certificate2 clientCertInRequest = Request.HttpContext.Connection.ClientCertificate;
if (!clientCertInRequest.Verify() || !AllowedCerialNumbers(clientCertInRequest.SerialNumber))
{
Response.StatusCode = 404;
return null;
}This validation logic first checks the certificate's validity and then verifies if the serial number is in the allowed list, ensuring only authorized clients can access protected resources.
Environment-Specific Certificate Configuration
In actual deployments, different environments may require different certificate configurations. The following method dynamically retrieves certificate subjects based on environment names:
protected internal static string GetCertificateSubjectNameBasedOnEnvironment(string environment)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile($"appsettings.{environment}.json", optional: false);
var configuration = builder.Build();
return configuration["ServerCertificateSubject"];
}This approach allows development, testing, and production environments to use different certificates, enhancing configuration flexibility.
Cross-Platform Compatibility Considerations
Although .NET Core supports cross-platform deployment, platform differences must be considered when handling client certificates. On Linux systems, you might encounter SSL connection errors like CURLE_SSL_CONNECT_ERROR 35, often related to underlying libcurl library configurations. Thorough testing on target platforms is recommended to ensure correct certificate configuration.
Best Practices and Security Recommendations
When implementing two-way SSL authentication, follow these best practices: use strong cryptographic algorithms and sufficient key lengths; regularly rotate certificates; update certificates before they expire; check certificate status using Certificate Revocation Lists (CRL) or Online Certificate Status Protocol (OCSP); log certificate validation failures without exposing sensitive details.
Conclusion
By correctly configuring HttpClientHandler, properly managing certificate stores, appropriately setting up Kestrel servers, and integrating authentication middleware, you can implement robust two-way SSL authentication mechanisms in .NET Core applications. This solution not only provides high-level security assurance but also maintains code maintainability and cross-platform compatibility. Developers should fully consider security best practices during implementation to ensure overall system security.