I have been trying to get a simple HTTPS secured Kestrel service running which validates clients using an installed self-signed root certificate (from a 3rd party). I am struggling to find what is specifically is wrong with the client certificate and why the service is bouncing the connection. Could someone answer categorically that Kestrel in .NET Core 3.1 on a linux box running OpenSSL 1.0.2k-fips 26 Jan 2017 no long accepts root certs which have a signature algorithm of md5RSA ?
I have been unable to fuind any way to find anything more specific from Kestrel.
I added the following to the program.cs to try to help:
private static bool ClientCertificateValidation(X509Certificate2 clientCertificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
StringBuilder sb = new StringBuilder();
int certNumber = 0;
foreach (X509ChainElement element in chain.ChainElements)
{
certNumber ;
var errors = element.ChainElementStatus;
List<string> errorList = new List<string>();
foreach(var cError in errors)
{
errorList.Add(cError.StatusInformation);
}
sb.AppendLine("Certificate #" certNumber ": (" string.Join(",", errorList.ToArray()) ")");
sb.AppendLine(" Subject: " element.Certificate.Subject);
sb.AppendLine(" Issuer: " element.Certificate.Issuer);
sb.AppendLine(" Serial #: " element.Certificate.SerialNumber);
sb.AppendLine(" Thumbprint: " element.Certificate.Thumbprint);
sb.AppendLine(" Valid Dates: " element.Certificate.NotBefore.ToString() " to " element.Certificate.NotAfter.ToString());
sb.AppendLine(" Signature Algorithm: " element.Certificate.SignatureAlgorithm.FriendlyName);
sb.AppendLine(" Version: " element.Certificate.Version);
sb.AppendLine(" Encoded Certificate: " Convert.ToBase64String(element.Certificate.Export(X509ContentType.Cert)));
}
Console.WriteLine(sb.ToString());
if (sslPolicyErrors.HasFlag(SslPolicyErrors.None))
{
Console.WriteLine($"***************** NO POLICY ERRORS! **********************");
return true;
}
return false;
}
Calling it via:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureKestrel(options =>
{
options.ConfigureHttpsDefaults(
httpsOptions =>
{
httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
httpsOptions.SslProtocols = SslProtocols.Tls12;
httpsOptions.ClientCertificateValidation =ClientCertificateValidation;
});
});
});
But truly "Certificate signature failure" gives me little to go on. Having run openssl verify - the result is OK....So what is Kestrel doing?
Thanks in advance
UPDATE:
The self signed (3rd party) certificate is installed on the server to validate the 3rd party's clients. The command mentioned does return an error though as the cert was supplied by a 3rd party I am unsure what the problem with it is?
CodePudding user response:
Okay, so both dotnet and openssl agree the signature is invalid. Although I don't see a practical way to reproduce this, 'unknown digest' (instead of 'bad padding' or 'out of range') suggests the signature was in fact created by the issuer (i.e. not corrupted data or signature, or wrong key) but the signer did it wrong. Try the following procedure (I used my own cert since yours is too private for anybody to see):
$ openssl req -newkey rsa:1024 -keyout 70348834.key -nodes -x509 -md5 -subj /CN=70348834 -out 70348834.crt
Generating a RSA private key
.....
....
writing new private key to '70348834.key'
-----
# RSA-1024 no longer meets standards but this is just for testing
$ openssl verify -check_ss_sig -CAfile 70348834.crt 70348834.crt
70348834.crt: OK
$ openssl asn1parse -i <70348834.crt
0:d=0 hl=4 l= 514 cons: SEQUENCE
4:d=1 hl=4 l= 363 cons: SEQUENCE
8:d=2 hl=2 l= 3 cons: cont [ 0 ]
10:d=3 hl=2 l= 1 prim: INTEGER :02
13:d=2 hl=2 l= 20 prim: INTEGER :39163AA0A0B6898D0DF0304F4F8D5649507B4877
35:d=2 hl=2 l= 13 cons: SEQUENCE
37:d=3 hl=2 l= 9 prim: OBJECT :md5WithRSAEncryption
48:d=3 hl=2 l= 0 prim: NULL
50:d=2 hl=2 l= 19 cons: SEQUENCE
52:d=3 hl=2 l= 17 cons: SET
54:d=4 hl=2 l= 15 cons: SEQUENCE
56:d=5 hl=2 l= 3 prim: OBJECT :commonName
61:d=5 hl=2 l= 8 prim: UTF8STRING :70348834
71:d=2 hl=2 l= 30 cons: SEQUENCE
73:d=3 hl=2 l= 13 prim: UTCTIME :211217042113Z
88:d=3 hl=2 l= 13 prim: UTCTIME :220116042113Z
103:d=2 hl=2 l= 19 cons: SEQUENCE
105:d=3 hl=2 l= 17 cons: SET
107:d=4 hl=2 l= 15 cons: SEQUENCE
109:d=5 hl=2 l= 3 prim: OBJECT :commonName
114:d=5 hl=2 l= 8 prim: UTF8STRING :70348834
124:d=2 hl=3 l= 159 cons: SEQUENCE
127:d=3 hl=2 l= 13 cons: SEQUENCE
129:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption
140:d=4 hl=2 l= 0 prim: NULL
142:d=3 hl=3 l= 141 prim: BIT STRING
286:d=2 hl=2 l= 83 cons: cont [ 3 ]
288:d=3 hl=2 l= 81 cons: SEQUENCE
290:d=4 hl=2 l= 29 cons: SEQUENCE
292:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Subject Key Identifier
297:d=5 hl=2 l= 22 prim: OCTET STRING [HEX DUMP]:041438C135B9D18DF0668B0AA31933FE0F947FBEDF84
321:d=4 hl=2 l= 31 cons: SEQUENCE
323:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Authority Key Identifier
328:d=5 hl=2 l= 24 prim: OCTET STRING [HEX DUMP]:3016801438C135B9D18DF0668B0AA31933FE0F947FBEDF84
354:d=4 hl=2 l= 15 cons: SEQUENCE
356:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Basic Constraints
361:d=5 hl=2 l= 1 prim: BOOLEAN :255
364:d=5 hl=2 l= 5 prim: OCTET STRING [HEX DUMP]:30030101FF
371:d=1 hl=2 l= 13 cons: SEQUENCE
373:d=2 hl=2 l= 9 prim: OBJECT :md5WithRSAEncryption
384:d=2 hl=2 l= 0 prim: NULL
386:d=1 hl=3 l= 129 prim: BIT STRING
# the number before the colon on the last line is the offset of the raw signature
$ openssl asn1parse <70348834.crt -strparse 386 -out 70348834.sig
Error in encoding
139775850254976:error:0D07207B:asn1 encoding routines:ASN1_get_object:header too long:../crypto/asn1/asn1_lib.c:101:
# ignore that error; RSA signature isn't ASN.1, but -strparse still extracts it, see:
$ ls -l 70348834.sig
-rwxrwxrwx 1 dthomps dthomps 128 Dec 16 23:27 70348834.sig
$ openssl rsautl -verify -certin -inkey 70348834.crt -in 70348834.sig -asn1parse
0:d=0 hl=2 l= 32 cons: SEQUENCE
2:d=1 hl=2 l= 12 cons: SEQUENCE
4:d=2 hl=2 l= 8 prim: OBJECT :md5
14:d=2 hl=2 l= 0 prim: NULL
16:d=1 hl=2 l= 16 prim: OCTET STRING
0000 - 2b 7c cf 6d c8 0f 53 82-0b 57 64 4d 5a e0 d6 9a |.m..S..WdMZ...
# FYI rsautl -verify isn't properly a verify operation in cryptographic terms,
# technically it's only the 'recover' part of verify-with-recovery (only for RSA)
Your 'recovered' signature should look like my last block above except for the data in the OCTET STRING (but it should still be the same length, l=16); if not complain to the cert issuer or provider that they've given you an invalid certificate.