WebRequest的不发送客户端证书 [英] WebRequest not sending client certificate

查看:269
本文介绍了WebRequest的不发送客户端证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在写一个客户端的REST API,并为我必须使用对我提供了一个证书的API认证。



这代码如下:

 公共字符串GetCustomer(INT CUSTID)
{
X509Certificate2证书=新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/+客户ID);
req.ClientCertificates.Add(证书);

req.UserAgent =LOL API客户端;
req.Accept =应用/ JSON;
req.Method = WebRequestMethods.Http.Get;

字符串结果= NULL;
使用(HttpWebResponse RESP =(HttpWebResponse)req.GetResponse())
{
StreamReader的读者=新的StreamReader(resp.GetResponseStream());
结果= reader.ReadToEnd();
}
返回结果;
}



每次我让我得到一个错误400的请求,并使用招的时候看我得到以下



响应

 < HTML和GT; 
< HEAD><标题> 400。不需要SSL证书被送到< /标题>< /头>
<车身的bgcolor =白>
<中心及GT;< H1> 400错误的请求和LT; / H1>< /中心及GT;
<中心及GT;没有必要的SSL证书被送到< /中心及GT;
<小时><中心及GT;的nginx / 0.6.32< /中心及GT;
< /身体GT;
< / HTML>



我认为没有理由为它不发送证书,但排除SSL也不太容易。我确实添加了一些调试语句来添加一些细节和使用招停了下来,他是我得到了什么



这些错误是由ValidateServerCertificate()

 证书错误:RemoteCertificateChainErrors 
NotSignatureValid
证书的签名无法验证。
1048576
未知错误。



这是从被抛出WebExecption错误。

 例外毫无遗漏ProtocolError 
远程服务器返回错误:(400)错误的请求。
错误请求
< HTML和GT;
< HEAD><标题> 400。不需要SSL证书被送到< /标题>< /头>
<车身的bgcolor =白>
<中心及GT;< H1> 400错误的请求和LT; / H1>< /中心及GT;
<中心及GT;没有必要的SSL证书被送到< /中心及GT;
<小时><中心及GT;的nginx / 0.6.32< /中心及GT;
< /身体GT;
< / HTML>

这是ValidateServerCertificate()code..it总是返回true忽略任何证书错误。

 公共静态布尔ValidateServerCertificate(对象发件人,X509证书证书,X509Chain链,sslPolicyErrors sslPolicyErrors)
{
如果( sslPolicyErrors == SslPolicyErrors.None)
返回真;

如果(sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors)
{
Console.WriteLine(证书错误:{0},sslPolicyErrors);
的foreach(在chain.ChainStatus VAR chainstat)
{
Console.WriteLine({0},chainstat.Status);
Console.WriteLine({0},chainstat.StatusInformation);
}
返回真;
}

Console.WriteLine(证书错误:{0},sslPolicyErrors);

//允许该客户端与未经认证的服务器通信。
返回真;
}


解决方案

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

 公共字符串GetCustomer(INT CUSTID)
{
/ /编辑此匹配您的客户端证书:十六进制的主题密钥标识符。
串执行subjectKeyIdentifier =39b66c2a49b2059a15adf96e6b2a3cda9f4b0e3b;

的X509Store店=新的X509Store(我,StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);

X509Certificate2Collection证书= store.Certificates.Find(X509FindType.FindBySubjectKeyIdentifier,执行subjectKeyIdentifier,真正的);
X509Certificate2证书=证书[0];

HttpWebRequest的REQ =(HttpWebRequest的)WebRequest.Create(https://api.foo.net/api/customer/v1/+客户ID);
req.ClientCertificates.Add(证书);

req.UserAgent =LOL API客户端;
req.Accept =应用/ JSON;
req.Method = WebRequestMethods.Http.Get;

字符串结果= NULL;
使用(HttpWebResponse RESP =(HttpWebResponse)req.GetResponse())
{
StreamReader的读者=新的StreamReader(resp.GetResponseStream());
结果= reader.ReadToEnd();
}
返回结果;
}

请参阅的导入证书的说明。该代码假定您已经导入证书与公共密钥和私有密钥的个人证书文件夹(我),当前用户的。



您不需要提供一个 ServicePointManager.ServerCertificateValidationCallback 。这使得你的应用程序更改服务器证书如何验证。这不会影响服务器如何验证您的客户端证书。


I'm writing a client for a REST API and to authenticate to the API I must use a cert that was provided to me.

this code is as follows:

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

Each time I make the request I get an error 400 and when using Fiddler to look at the response I get the following

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

I see no reason for it not to send the cert but troubleshooting SSL isn't terribly easy. I did add some debug statements to add some detail and stopped using fiddler and he is what I got

These errors are from ValidateServerCertificate()

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

These are the errors from the WebExecption that is thrown.

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>

This is the ValidateServerCertificate() code..it always returns true to ignore any cert errors.

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

解决方案

Your code loads the client certificate from a local file. You should have more success if you import the client certificate into the certificate store (which is highly recommended to protect the private key). Then your code should look more like this:

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

See Import a Certificate for instructions. The code assumes that you have imported the certificate with both public and private keys to the Personal certificates folder ("My") of the Current User.

You do not need to supply a ServicePointManager.ServerCertificateValidationCallback. That allows your application to change how the server certificate is validated. That does not influence how the server validates your client certificate.

这篇关于WebRequest的不发送客户端证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆