I have a p12 file that contains three certificates (and a private key)
- Client certificate
- Intermediate certificate
- Root certificate
Using openssl s_client the connection is successful, however, using HTTP client the connection isn't.
Inspecting the payload in Wireshark I can see that only two certificates are sent (1,2) and the root (3) is missing.
I've installed the certificates in Current User and Local Machine in My and Root Certificates but nothing changes the result. Where should the certificates be installed?
Fun fact, using var chain = new X509Chain(); chain.Build(certificate)
all intermediate certificates are correctly found.
Update: I tried adding all certificates resolved from the chain but the result is the same.
Code
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
const string thumbprint = "";
using var store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var certificate = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false)[0];
var clientHandler = new HttpClientHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual,
SslProtocols = SslProtocols.Tls12,
ClientCertificates = { certificate }
};
var client = new HttpClient(clientHandler)
{
BaseAddress = new Uri("url")
};
var response = await client.GetAsync(string.Empty);
// Exception:
// The SSL connection could not be established, see inner exception.' ->
// AuthenticationException: Authentication failed because the remote party sent a TLS alert: 'HandshakeFailure'.
I've been follow this SO-post but it doesn't work for me.
CodePudding user response:
Where should the certificates be installed?
on a server you are connecting to.
The idea behind this is that you send leaf and all intermediate CA certificates to server. Server builds the certificate chain on receipt. And if server is not able to locate the root certificate, then client certificate is not trusted by the server and validation check will fail. Presence of root certificate in request makes little sense, because server will not automatically trust your root just because you sent it. Root certificate must be explicitly installed on a server in trusted root store.
An excerpt from RFC 5246 §7.4.2 which applies to both, server and client certificates:
certificate_list
This is a sequence (chain) of certificates. The sender's
certificate MUST come first in the list. Each following
certificate MUST directly certify the one preceding it. Because
certificate validation requires that root keys be distributed
independently, the self-signed certificate that specifies the root
certificate authority MAY be omitted from the chain, under the
assumption that the remote end must already possess it in order to
validate it in any case.
In other words, there is nothing you can or should do on your end.
CodePudding user response:
You can add this to your client handler initialization:
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };