I am attempting to send a self-signed client certificate using HttpClient with the following code:
var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(GetClientCertificate()); //Loads cert from a .pfx file
var client = new HttpClient(handler);
PerformRequest(client);
I've seen a dozen SO posts related to this, but none have resolved my issue.
Things to note:
HttpClient is not sending one.

handler.SslProtocols to 1.0, 1.1, 1.2 -- none workX509Certificate2 returned from GetClientCertificate() has a private keyI have been troubleshooting this for 3 days now and even read through the reference source trying to figure out why my cert isn't included, but I can't find a reason.
I suspect somewhere deep inside the HttpClient implementation, my cert is getting rejected because it is self-signed.
How can I force it to send my cert? (the server maintains a whitelist, so I don't care if it thinks my cert is invalid). Or, at bare minimum, how can I get any sort of debugging information out of this? Is there any way to get a reason why a cert is rejected?
Update:
After enabling tracing, I have found that .NET is correctly selecting my certificate:
System.Net Information: 0 : [23960] SecureChannel#64538993 - Selected certificate: <omitted>
System.Net Information: 0 : [23960] SecureChannel#64538993 - Left with 1 client certificates to choose from.
System.Net Information: 0 : [23960] SecureChannel#64538993 - Trying to find a matching certificate in the certificate store.
System.Net Information: 0 : [23960] SecureChannel#64538993 - Locating the private key for the certificate: <omitted>
System.Net Information: 0 : [23960] SecureChannel#64538993 - Certificate is of type X509Certificate2 and contains the private key.
System.Net Information: 0 : [23960] SecureChannel#64538993::.AcquireClientCredentials, new SecureCredential() (flags=(ValidateManual, NoDefaultCred, SendAuxRecord), m_ProtocolFlags=(Tls12Client), m_EncryptionPolicy=RequireEncryption)
System.Net Information: 0 : [23960] AcquireCredentialsHandle(package = Microsoft Unified Security Protocol Provider, intent = Outbound, scc = System.Net.SecureCredential)
System.Net Information: 0 : [23960] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 21c5cd98:21cd2108, targetName = <omitted>, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [23960] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=100, returned code=ContinueNeeded).
... etc
However, it is still not being sent. Any more ideas on where to look would be greatly appreciated.
This answer led me to the solution.
X509Certificate2.PrivateKey was throwing a NotSupportedException because I was using ECD as the signature algorithm. I switched to RSA and now it properly sends the certificate.
What's strange is that tracing showed no issue with the ECD cert, and it was able to successfully identify the private key. I have no idea why this is the case -- it sounds like a bug to me. Nevertheless, RSA will work for my use case and I am tired of debugging this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With