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:
- I have verified via Wireshark that the server is requesting a client cert, but
HttpClient
is not sending one.
- The exact same certificate (same .pfx file is used) is sent when I use Postman to perform the request
- I have tried forcing the TLS version via
handler.SslProtocols
to 1.0, 1.1, 1.2 -- none work - The
X509Certificate2
returned fromGetClientCertificate()
has a private key - This is on .NET Framework 4.7.2 -- I can't change this
I 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.