C# 使用不在证书存储区中的客户端证书
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1643636/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using client certificate not in certificate store
提问by nothrow
I'm trying to authenticate myself against WebService using my client certificate, but, for some reasons (I explain), I don't want to load certificate from store, rather read it from disc.
我正在尝试使用我的客户端证书对 WebService 进行身份验证,但是由于某些原因(我解释过),我不想从商店加载证书,而是从光盘中读取它。
The following:
下列:
// gw is teh WebService client
X509Certificate cert = new X509Certificate(PathToCertificate);
_gw.ClientCertificates.Add(ClientCertificate());
ServicePointManager.ServerCertificateValidationCallback = (a,b,c,d) => true;
_gw.DoSomeCall();
returns always 403 - the Service doesn't authorize me. But, when I save that certificate into CertStore, it works. (As stated in MSDN.)
始终返回 403 - 服务未授权我。但是,当我将该证书保存到 CertStore 中时,它就可以工作了。(如 MSDN 中所述。)
Is it possible to use certificate not in store?
是否可以使用不在商店中的证书?
(the reason is, that I got windows service(client) sometimes calling webservice(server), and after unspecified amount of time the service 'forgets' my certificates and doesnt authorize against server, with no apparent reason)
(原因是,我的 Windows 服务(客户端)有时会调用 web 服务(服务器),并且在未指定的时间后,该服务“忘记”了我的证书并且没有对服务器进行授权,没有明显的原因)
采纳答案by Gonzalo
What type of file is PathToCertificate? If it's just a .cer file, it will not contain the private key for the certificate and trying to use that certificate for SSL/TLS will fail.
PathToCertificate 是什么类型的文件?如果它只是一个 .cer 文件,它将不包含证书的私钥,并且尝试将该证书用于 SSL/TLS 将失败。
However, if you have a PKCS7 or PKCS12 file that includes the public and private key for the certificate, your code will work (you might need to use the overload that takes a password if the private key has one).
但是,如果您有一个包含证书公钥和私钥的 PKCS7 或 PKCS12 文件,您的代码将起作用(如果私钥有密码,您可能需要使用带密码的重载)。
To test this, I went to http://www.mono-project.com/UsingClientCertificatesWithXSPand created my client.p12 file following those instructions. I also created a simple HTTPS server using HttpListener for testing.
为了对此进行测试,我访问了http://www.mono-project.com/UsingClientCertificatesWithXSP并按照这些说明创建了我的 client.p12 文件。我还使用 HttpListener 创建了一个简单的 HTTPS 服务器进行测试。
Then I compiled the following program into 'client.exe' and run like:
然后我将以下程序编译成“client.exe”并运行如下:
client.exe https://<MYSSLSERVER>/ client.p12 password
where client.p12 is the PKCS12 file generated before and 'password' is the password I set for the private key of the certificate.
其中client.p12是之前生成的PKCS12文件,'password'是我为证书私钥设置的密码。
using System;
using System.IO;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text;
public class HttpWebRequestClientCertificateTest : ICertificatePolicy {
public bool CheckValidationResult (ServicePoint sp, X509Certificate certificate,
WebRequest request, int error)
{
return true; // server certificate's CA is not known to windows.
}
static void Main (string[] args)
{
string host = "https://localhost:1234/";
if (args.Length > 0)
host = args[0];
X509Certificate2 certificate = null;
if (args.Length > 1) {
string password = null;
if (args.Length > 2)
password = args [2];
certificate = new X509Certificate2 (args[1], password);
}
ServicePointManager.CertificatePolicy = new HttpWebRequestClientCertificateTest ();
HttpWebRequest req = (HttpWebRequest) WebRequest.Create (host);
if (certificate != null)
req.ClientCertificates.Add (certificate);
WebResponse resp = req.GetResponse ();
Stream stream = resp.GetResponseStream ();
StreamReader sr = new StreamReader (stream, Encoding.UTF8);
Console.WriteLine (sr.ReadToEnd ());
}
}
Let me know if you want me to upload the server code and the certificates used on both sides of the test.
如果您希望我上传测试双方使用的服务器代码和证书,请告诉我。
回答by jle
Do you need a password for the certificate? If so, there is a field for it in the constructor.
证书需要密码吗?如果是这样,构造函数中有一个字段。
X509Certificate cert = new X509Certificate(PathToCertificate,YourPassword);
回答by csharptest.net
You have the potential for at least two problems...
你至少有两个问题的潜力......
First...
第一的...
Your client certificate file cannot contain a private key unless it's accessed with a password. You should be using a PKCS #12 (*.pfx) certificate with a password so that your client has access to the private key. You client code will have to provide the password when opening the certificate as others have already posted. There are several ways to create this, the easiest is to use the following command-line to first generate the certificate, then use the MMC certificate manager to export the certificates private key:
除非使用密码访问,否则您的客户端证书文件不能包含私钥。您应该使用带有密码的 PKCS #12 (*.pfx) 证书,以便您的客户端可以访问私钥。您的客户端代码在打开证书时必须提供密码,因为其他人已经发布了。创建这个有几种方法,最简单的就是使用下面的命令行先生成证书,然后使用MMC证书管理器导出证书私钥:
Process p = Process.Start(
"makecert.exe",
String.Join(" ", new string[] {
"-r",// Create a self signed certificate
"-pe",// Mark generated private key as exportable
"-n", "CN=" + myHostName,// Certificate subject X500 name (eg: CN=Fred Dews)
"-b", "01/01/2000",// Start of the validity period; default to now.
"-e", "01/01/2036",// End of validity period; defaults to 2039
"-eku",// Comma separated enhanced key usage OIDs
"1.3.6.1.5.5.7.3.1," +// Server Authentication (1.3.6.1.5.5.7.3.1)
"1.3.6.1.5.5.7.3.2", // Client Authentication (1.3.6.1.5.5.7.3.2)
"-ss", "my",// Subject's certificate store name that stores the output certificate
"-sr", "LocalMachine",// Subject's certificate store location.
"-sky", "exchange",// Subject key type <signature|exchange|<integer>>.
"-sp",// Subject's CryptoAPI provider's name
"Microsoft RSA SChannel Cryptographic Provider",
"-sy", "12",// Subject's CryptoAPI provider's type
myHostName + ".cer"// [outputCertificateFile]
})
);
Second...
第二...
Your next problem is going to be server-side. The server has to allow this certificate. You have the right logic, but on the wrong side of the wire, move this line to the web server handling the request. If you cannot, you must then take the '.cer' file saved above to the server and add it to the server computer's trust list:
您的下一个问题将是服务器端。服务器必须允许此证书。您有正确的逻辑,但在线路的错误一侧,将此行移动到处理请求的 Web 服务器。如果不能,则必须将上面保存的“.cer”文件带到服务器并将其添加到服务器计算机的信任列表中:
ServicePointManager.ServerCertificateValidationCallback = (a,b,c,d) => true;
回答by PanJanek
The potential problem could be caching of SSL sessions (Schannel cache). Only first request negotiates the SSL handshake. Subsequent requests will use the same session ID and hope that the server accept it. If the server clears the SessionId, the requests will fail with 403 error. To disable local ssl session caching (and force SSL negotiation for each request) you have to open windows registry folder:
潜在的问题可能是 SSL 会话的缓存(Schannel 缓存)。只有第一个请求协商 SSL 握手。后续请求将使用相同的会话 ID,并希望服务器接受它。如果服务器清除 SessionId,请求将失败并显示 403 错误。要禁用本地 ssl 会话缓存(并为每个请求强制 SSL 协商),您必须打开 Windows 注册表文件夹:
[HKEY_LOCAL_MACHINE][System][CurrentControlSet][Control][SecurityProviders][SCHANNEL]
[HKEY_LOCAL_MACHINE][系统][CurrentControlSet][Control][SecurityProviders][SCHANNEL]
and add the key named ClientCacheTime (DWORD) with value 0.
并添加值为 0 的名为 ClientCacheTime (DWORD) 的键。
This issue is covered here:
此处介绍了此问题: