WebRequest不发送客户端证书

我正在为REST API编写客户端并对API进行身份validation我必须使用提供给我的证书。

这段代码如下:

public string GetCustomer(int custId) { X509Certificate2 Cert = new X509Certificate2(); Cert.Import(@"C:\users\foo\desktop\api\pubAndPrivateCert.pkcs12", "", X509KeyStorageFlags.PersistKeySet); ServicePointManager.ServerCertificateValidationCallback += ValidateServerCertificate; HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://api.foo.net/api/customer/v1/" + custId); req.ClientCertificates.Add(Cert); req.UserAgent = "LOL API Client"; req.Accept = "application/json"; req.Method = WebRequestMethods.Http.Get; string result = null; using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse()) { StreamReader reader = new StreamReader(resp.GetResponseStream()); result = reader.ReadToEnd(); } return result; } 

每次我发出请求时都会收到错误400,当使用Fiddler查看响应时,我得到以下内容

  400 No required SSL certificate was sent  

400 Bad Request

No required SSL certificate was sent
nginx/0.6.32

我认为没有理由不发送证书,但对SSL进行故障排除并不是非常容易。 我添加了一些调试语句来添加一些细节并停止使用fiddler,他就是我得到的

这些错误来自ValidateServerCertificate()

 Certificate error: RemoteCertificateChainErrors NotSignatureValid The signature of the certificate cannot be verified. 1048576 Unknown error. 

这些是引发的WebExecption的错误。

 Cought Exception ProtocolError The remote server returned an error: (400) Bad Request. BadRequest  400 No required SSL certificate was sent  

400 Bad Request

No required SSL certificate was sent
nginx/0.6.32

这是ValidateServerCertificate()代码。总是返回true以忽略任何证书错误。

  public static bool ValidateServerCertificate(object sender, X509Certificate certificate,X509Chain chain,SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.None) return true; if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors) { Console.WriteLine("Certificate error: {0}", sslPolicyErrors); foreach (var chainstat in chain.ChainStatus) { Console.WriteLine("{0}", chainstat.Status); Console.WriteLine("{0}", chainstat.StatusInformation); } return true; } Console.WriteLine("Certificate error: {0}", sslPolicyErrors); // allow this client to communicate with unauthenticated servers. return true; } 

您的代码从本地文件加载客户端证书。 如果将客户端证书导入证书存储区(强烈建议保护私钥),则应该取得更大成功。 然后你的代码看起来应该更像这样:

 public string GetCustomer(int custId) { // EDIT THIS TO MATCH YOUR CLIENT CERTIFICATE: the subject key identifier in hexadecimal. string subjectKeyIdentifier = "39b66c2a49b2059a15adf96e6b2a3cda9f4b0e3b"; X509Store store = new X509Store("My", StoreLocation.CurrentUser); store.Open(OpenFlags.ReadOnly); X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindBySubjectKeyIdentifier, subjectKeyIdentifier, true); X509Certificate2 certificate = certificates[0]; HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://api.foo.net/api/customer/v1/" + custId); req.ClientCertificates.Add(certificate); req.UserAgent = "LOL API Client"; req.Accept = "application/json"; req.Method = WebRequestMethods.Http.Get; string result = null; using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse()) { StreamReader reader = new StreamReader(resp.GetResponseStream()); result = reader.ReadToEnd(); } return result; } 

有关说明,请参阅导入证书 。 该代码假定您已将包含公钥和私钥的证书导入到当前用户的个人证书文件夹(“我的”)。

您不需要提供ServicePointManager.ServerCertificateValidationCallback 。 这允许您的应用程序更改服务器证书的validation方式。 这不会影响服务器validation客户端证书的方式。