Add Client Certificate to .Net Core Httpclient

Add client certificate to .NET Core HttpClient

Make all configuration in Main() like this:

public static void Main(string[] args)
{
var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
var logger = new LoggerConfiguration().ReadFrom.Configuration(configuration).CreateLogger();
string env="", sbj="", crtf = "";

try
{
var whb = WebHost.CreateDefaultBuilder(args).UseContentRoot(Directory.GetCurrentDirectory());

var environment = env = whb.GetSetting("environment");
var subjectName = sbj = CertificateHelper.GetCertificateSubjectNameBasedOnEnvironment(environment);
var certificate = CertificateHelper.GetServiceCertificate(subjectName);

crtf = certificate != null ? certificate.Subject : "It will after the certification";

if (certificate == null) // present apies even without server certificate but dont give permission on authorization
{
var host = whb
.ConfigureKestrel(_ => { })
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.UseConfiguration(configuration)
.UseSerilog((context, config) =>
{
config.ReadFrom.Configuration(context.Configuration);
})
.Build();
host.Run();
}
else
{
var host = whb
.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);
});
})
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls("https://*:443")
.UseStartup<Startup>()
.UseConfiguration(configuration)
.UseSerilog((context, config) =>
{
config.ReadFrom.Configuration(context.Configuration);
})
.Build();
host.Run();
}

Log.Logger.Information("Information: Environment = " + env +
" Subject = " + sbj +
" Certificate Subject = " + crtf);
}
catch(Exception ex)
{
Log.Logger.Error("Main handled an exception: Environment = " + env +
" Subject = " + sbj +
" Certificate Subject = " + crtf +
" Exception Detail = " + ex.Message);
}
}

Configure file startup.cs like this:

#region 2way SSL settings
services.AddMvc();
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();
});

services.AddAuthorization(options =>
{
options.AddPolicy("CanAccessAdminMethods", policy => policy.RequireRole("Admin"));
options.AddPolicy("CanAccessUserMethods", policy => policy.RequireRole("User"));
});
#endregion

The certificate helper

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;
}
}

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"];
}
}

ASP.NET Core 2.1: Add client certificate to registered typed HTTP clients

You are correct in your experience that AddHttpMessageHandler is required to return a type of DelegatingHandler as this function is used to extend the request pipeline. In order to create an HttpClientHandler with a client certificate attached, you should instead use ConfigurePrimaryHttpMessageHandler to create and return the configured instance of HttpClientHandler.

.NET Core adding client certificate to POST to Kestrel REST API on Linux fails server cert validation

Turns out this is actually working! I just needed to get the correct certificates in place!

Specifically, I had to include the Root CA and Intermediate CA at the Server side.

The Client side, I had to include only the Root CA to verify.

HttpClient connecting via certification validation

The error complains that the server certificate is invalid. Perhaps it has expired or revoked. Sometimes the root authority certificate itself is compromised and revoked. This is rare but it has happened in the past.

Perhaps a test server uses a self-signed certificate for development. Self-signed certificates are invalid by definition because they aren't signed by a trusted authority.

HTTPS isn't used to encrypt the connection, it's used to ensure that no other server gets "in the middle" of the client and server. It does that by ensuring the remote server is who its certificate says it is. Obviously, the certificate needs to be valid - which means it needs to be signed by a trusted source. Without validation someone could add a malicious proxy to your network that would pose as the remote server, intercept your calls and send them to the remote server.

If the server service has expired or been revoked, the server admin will have to renew it.

To use a self-signed certificate without compromising security is to trust it. The .NET Core SDK will add the self-signed certificate used by .NET Core projects to the trusted certificates of the local machine. On other machines you can navigate to the API URL with a browser, click on the warning that appears at the left of the address bar and trust the certificate



Related Topics



Leave a reply



Submit