我正在开发简单的Windows服务,从远程Web服务发送和接收数据。 我决定使用WebClient类来实现它的简单性并增强它以在请求中包含证书,如下所示:
class MyWebClient : WebClient
{
public X509Certificate cert { set; get; }
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest req = (HttpWebRequest)base.GetWebRequest(address);
req.ClientCertificates.Clear();
req.ClientCertificates.Add(cert);
return req;
}
}
这就是我准备和提出请求的方式:
try {
//...
string qry = "Some xml query...";
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate(object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors) { return true; };
X509Certificate cert = X509Certificate.CreateFromCertFile(appPath + @"\data\cert.der");
MyWebClient cl = new MyWebClient();
cl.cert = cert;
string xmlReq = qry;
cl.Headers[HttpRequestHeader.ContentType] = "text/xml";
var data = Encoding.UTF8.GetBytes(xmlReq);
byte[] res = cl.UploadData(apiUrl, data);
cl.Dispose();
string result = Encoding.UTF8.GetString(res);
} catch (Exception ex) {
//...
}
//...
现在,我知道从文件加载证书不是最好的主意,但这不是重点。关键是上面的代码在桌面应用程序中完美运行,但在Windows服务中抛出“无法为SSL / TLS建立安全通道”异常。 我尝试在“localService”和“networkService”帐户下安装该服务,但没有任何不同。
更新:在“用户”下安装也没有帮助。 我错过了什么吗?
答案 0 :(得分:2)
使用以下方法加载证书时:
X509Certificate cert = X509Certificate.CreateFromCertFile(appPath + @"\data\cert.der");
您只是加载证书。但是,要使客户端证书身份验证起作用,您需要也提供私钥(否则,任何人都可以使用任何证书)。
在聊天室讨论之后,您已经表明您还有.p12
(PKCS#12),.key
和.pem
文件,以及{{ 1}}你试图加载的文件。
通常,这些扩展名以这种方式使用:
.der
用于DER编码(二进制)中的证书本身。.der
用于PEM编码中的证书本身(DER的base64编码,.pem
分隔符内)。---BEGIN....--- ... --- END ---
。.key
(或.p12
)用于PKCS#12文件,该文件将包含证书(可能还包含CA链)和私钥。在.Net中,基础.pfx
将不允许您加载私钥和证书。您应该考虑将p12文件加载到X509Certificate2
实例中:它本质上是一个便利类,它不仅可以为证书建模,还可以将私钥与对象关联。
我不确定为什么它可以用作桌面应用程序而不是服务。我的猜测是,它会在其中一种情况下自动从用户或机器商店中获取一个cert +私钥。无论哪种方式,您的桌面应用程序都无法使用DER文件进行身份验证。