我正在尝试通过HTTPS调用API。 API希望发送客户端证书,然后将对其进行验证。该API不会返回某些已接受CA的列表(例如在标准的Web服务器TLS流中),它只是希望证书可以验证。
在运行我的应用程序的客户端计算机上,客户端证书安装在本地计算机\个人存储中(通过在certlm.msc
中进行检查,它也可以正常运行)。我可以像这样HttpWebRequest
一样从商店中获取证书并将其添加到我的request.ClientCertificates.Add(cert)
中。在运行时检查应用程序代码中的证书,它具有私钥(HasPrivateKey
是true
,并且PrivateKey
属性包含数据)。为了进行测试,我授予了everyone
对证书的读取权限,以确保可以从应用程序中使用证书来检索它们的私钥,这似乎可行。
但是,API抱怨没有发送证书。使用Wireshark检查请求会显示TLSv1.2
类型的Certificate
握手,但是显示为Certificate Length: 0
的握手。因此确实没有发送证书。
使用Postman调用具有完全相同证书的完全相同的API(从文件中,因为Postman需要一个文件,该文件是在机器\个人存储中导入证书的.pfx
)发送证书。 Wireshark显示Certificate Length: 770
,我可以查看证书详细信息。
所以看来,由于某种原因,即使我将证书附加到HttpWebRequest.ClientCertificates
上,它也不会从应用程序代码中发送出去。也不例外,它不会被发送。
回顾:
HttpWebRequest.ClientCertificates
包含从计算机\个人存储中检索的证书certlm.msc
中的证书看起来不错(受信任的CA等)有什么主意我想念的吗?谢谢!
(稍后编辑)
我在框架中调试了SecureChannel
类,该类是处理证书发送的类,并发现了一些令人担忧的东西。首先,一些评论:
Here is how we work:
case 0: Cert Selection delegate is present
Alwasys use its result as the client cert answer.
Try to use cached credential handle whenever feasible.
Do not use cached anonymous creds if the delegate has returned null
and the collection is not empty (allow responding with the cert later).
case 1: Certs collection is empty
Always use the same statically acquired anonymous SSL Credential
case 2: Before our Connection with the Server
If we have a cached credential handle keyed by first X509Certificate
**content** in the passed collection, then we use that cached
credential and hoping to restart a session.
Otherwise create a new anonymous (allow responding with the cert later).
case 3: After our Connection with the Server (ie during handshake or re-handshake)
The server has requested that we send it a Certificate then
we Enumerate a list of server sent Issuers trying to match against
our list of Certificates, the first match is sent to the server.
Once we got a cert we again try to match cached credential handle if possible.
This will not restart a session but helps miminizing the number of handles we create.
调试代码,注释似乎成立:
// (see VsWhidbey#363953) For some (probably good) reason IIS does not renegotiate a restarted session if client cert is needed.
// So we don't want to reuse **anonymous** cached credential for a new SSL connection if the client has passed some certificate.
// The following block happens if client did specify a certificate but no cached creds were found in the cache
// Since we don't restart a session the server side can still challenge for a client cert.
...此代码之后...
if ((object)clientCertificate != (object)selectedCert)
selectedCert.Reset();
guessedThumbPrint = null;
selectedCert = null;
clientCertificate = null;
因此基本上,它将null
对我传入的证书的引用。如果我正确理解它,则可以解决某些IIS问题,这意味着它希望服务器将发证人列表发回给筛选证书的依据(这是注释中的情况3),这的确是我在代码中看到的。仅当此发行者列表从服务器中删除时,代码才会通过客户端证书并由发行者过滤,然后向上发送匹配的证书。
现在我不禁要问:如果服务器要求颁发者列表,是否只能发送客户端证书?因为就我而言,我正在调用的API并没有做到这一点,所以它只需要一个证书即可。我希望我是错的,并且有人可以阐明这一点。
(甚至以后进行编辑)
我正在调用的API现在返回CA列表。我的测试CA已添加到此处,并且在SSL握手期间返回了它。现在调试SecureChannel
表明我之前的假设是正确的:
SecureChannel
成功将其m_SelectedClientCertificate
设置为我的证书,但是... 一旦设置了SecureChannel.m_SelectedClientCertificate
,似乎SecureChannel
本身就不再使用它了,但是它被暴露了:
internal X509Certificate LocalClientCertificate {
get {
return m_SelectedClientCertificate;
}
}
不幸的是,在我的情况下,从未调用过此属性:(
答案 0 :(得分:1)
发现问题:我的证书已与SHA1签署。用SHA256辞职并看到它被发送了!