我尝试使用以下代码通过HttpClient
发送自签名的客户端证书:
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);
我看过许多关于此问题的 Stack Overflow 帖子,但没有一个解决了我的问题。
需要注意的事项:
- 通过 Wireshark 验证,服务器正在请求客户端证书,但
HttpClient
没有发送证书。
- 当我使用 Postman 发送请求时,使用相同的证书(相同的 .pfx 文件)。
- 我尝试通过
handler.SslProtocols
强制指定 TLS 版本为 1.0、1.1、1.2 —— 都无效。 GetClientCertificate()
返回的X509Certificate2
具有私钥。- 此代码运行在 .NET Framework 4.7.2 上 —— 我不能更改。
我已经进行了3天的故障排除,甚至阅读了参考源代码,试图弄清楚为什么我的证书未包含在内,但我找不到原因。
我怀疑在 HttpClient
实现的深处,我的证书因为是自签名而被拒绝。
如何强制它发送我的证书?(服务器维护白名单,所以我不在乎它认为我的证书是否无效)。 或者,至少如何从中获得任何调试信息? 有没有办法获取证书被拒绝的原因?
更新:
启用跟踪后,我发现 .NET 正确地选择了我的证书:
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
然而,它仍未被发送。若有其他查找建议,请不吝赐教。
Import-Certificate -FilePath $certFilePath -CertStoreLocation 'Cert:\LocalMachine\Root'
。 - Panagiotis Kanavos