Trying to get my head around mTLS and client certificate authentication.
Mutual TLS
- Application owner generates a root certificate
- Generated root certificate is used to generate a server certificate
- Generated root certificate is used to generate a client certificate
- Client certificate is sent to client to grant access to application
Could it possibly be used like this
- Application owner generates a root certificate
- Generated root certificate is used to generate a server certificate
- Client sends a certificate to be signed by root certificate
- Signed client certificate is used to grant access to application
- Instruct IIS Express to use server certificate and thus only accept client certificates issued by server certificate.
- Instruct Kestrel only accept client certificates signed by/issued by server certificate. Is this m-TLS?
CertificateAuthenticationEvents.OnCertificateValidatedis not called ifapp.UseAuthentication()is missing.- If revocation check fails the user can navigate to Home.
- Run file
certcrt.cmdand follow the instructions - Import client certificate to
Current User\Personal. This is usually done during creation.- Windows+R
- Type certmgr.exe then enter
- Right click Personal
- All Tasks > Import
- Select the generated
.cerclient file
- Import server certificate to
Local Computer\Trusted Root Certitificates Authorities- Windows+R
- Type certlm.exe then Ctrl+Shift+Enter (start as admin)
- Right click Trusted Root Certitificates Authorities
- All Tasks > Import
- Select the generated
.cerfile
- Import certificate revocation list. Same as above but select
.crlfile
Follow the steps in Application to setup authentication.
The certificate and password are read from environment variables and I've created a function to read them and create the certificate used for the server.
private static X509Certificate2 CreateServerCertificate()
{
// Error handling removed for brevity
const string envFilePath = "ASPNETCORE_Kestrel__Certificates__Default__Path";
const string envPassword = "ASPNETCORE_Kestrel__Certificates__Default__Password";
var cert = var password = Environment.GetEnvironmentVariable(envFilePath);
var password = Environment.GetEnvironmentVariable(envPassword);
return new X509Certificate2(cert, password);
}We need to configure Kestrel to request client certificate and we must provide a server certificate used to validate the client certificate. This is configured when the host is built, in this case in Program.cs.
webBuilder
.UseStartup<Startup>()
.ConfigureKestrel(options =>
{
options.ConfigureHttpsDefaults(https =>
{
https.ClientCertificateValidation += (certificate2, chain, errors) =>
{
// Perform any checks here
return true;
};
https.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
https.ServerCertificate = CreateServerCertificate();
});
});Is the above the mTLS part? Then the certificate authentication might not be needed if another security scheme is employed, example OAuth2 Client Credentials grant with bearer token. I would like to see that only client certificates signed by/issued by the server certificate are allowed to connect.
-
Should Kestrel configure server certificate automatically if present with values in
ASPNETCORE_Kestrel__Certificates__Default__{Path,Password}?It does, but the value in
HttpsConnectionAdapterOptions.ServerCertificateis not accessible. -
How to ensure that only client certificates signed by/issued by server certificate are allowed?
The specified network password is not correct
I saw this when I specified only file name in ASPNETCORE_Kestre__..Path and moved pfx to bin\Debug\netcoreapp3.1\.
Trying it again later correctly shows The specified file couldn't be found.
Check that the .pfx files are imported and not only .cer - maybe.
Run file iis.cmd to update relevant configuration sections. The section iisClientCertificateMappingAuthentication must be enabled and the section access should have sslFlags set to "Ssl, SslNegotiateCert, SslRequireCert"`.
-
Add
Microsoft.AspNetCore.Authentication.Certificatenuget package -
Configure authentication protocol
services .AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme) .AddCertificate(options => { options.AllowedCertificateTypes = CertificateTypes.All; options.Events = new CertificateAuthenticationEvents { OnCertificateValidated = context => { // Do validation on context.Certificate here return Task.CompletedTask; }, OnAuthenticationFailed = context => { return Task.CompletedTask; } }; });
-
Add
app.UseAuthentication()beforeapp.UseAuthorization()to hook intoCertificateAuthenticationEvents.OnCertificateValidated. This is never called otherwise, leaving open for any certificate.
HTTP Error 403.16 - Forbidden Your client certificate is either not trusted or is invalid.
See certificates step 2.
Warning: Certificate validation failed, subject was CN=ancc_client. RevocationStatusUnknown The revocation function was unable to check revocation for the certificate.
See certificates step 3 or disable recovation check options.RevocationMode = X509RevocationMode.NoCheck