WebRequest未发送客户端证书

本文关键字:客户端 证书 WebRequest | 更新日期: 2023-09-27 18:01:27

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

代码如下:

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查看响应时,我得到以下

<html>
<head><title>400 No required SSL certificate was sent</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<center>No required SSL certificate was sent</center>
<hr><center>nginx/0.6.32</center>
</body>
</html>

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

这些错误来自ValidateServerCertificate()

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

这些是webeexception抛出的错误。

Cought Exception ProtocolError
The remote server returned an error: (400) Bad Request.
BadRequest
<html>
<head><title>400 No required SSL certificate was sent</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<center>No required SSL certificate was sent</center>
<hr><center>nginx/0.6.32</center>
</body>
</html>

这是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;
    }

WebRequest未发送客户端证书

您的代码从本地文件加载客户端证书。如果将客户端证书导入到证书存储中(强烈建议这样做以保护私钥),您应该会更成功。那么你的代码应该看起来像这样:

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;
}

请参见导入证书获取说明。该代码假设您已经将带有公钥和私钥的证书导入到当前用户的个人证书文件夹("My")中。

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