我想我自己反对使用我的客户端证书的WebService身份验证,但是,由于种种原因(我解释一下),我不希望从存储区加载证书,而从磁盘读取它。
下列:
// gw is teh WebService client
X509Certificate cert = new X509Certificate(PathToCertificate);
_gw.ClientCertificates.Add(ClientCertificate());
ServicePointManager.ServerCertificateValidationCallback = (a,b,c,d) => true;
_gw.DoSomeCall();
总是返回403 - 服务没有授权我。 但是,当我保存证书到的CertStore,它的工作原理。 (如在MSDN说明。)
是否有可能使用证书不是在商店?
(原因是,我得到Windows服务(客户端)有时调用Web服务(服务器),以及时间不详量后,在服务“忘记”我的证书和犯规授权对服务器,没有明显的理由)
什么类型的文件是PathToCertificate? 如果它只是一个.CER文件,它将不包含证书的私钥,并尝试使用该证书的SSL / TLS将失败。
不过,如果你有一个包括证书的公钥和私钥一个PKCS7或PKCS12文件,你的代码就可以了(你可能需要使用,需要一个密码,如果私钥有一个过载)。
为了测试这个,我去http://www.mono-project.com/UsingClientCertificatesWithXSP并创建了client.p12文件遵循着这些指导。 我还创建使用HttpListener用于测试的简单HTTPS服务器。
然后,我整理了以下程序为“client.exe”并运行,如:
client.exe https://<MYSSLSERVER>/ client.p12 password
其中client.p12是之前和“密码”产生的PKCS12文件是我的证书的私钥设置密码。
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 ());
}
}
让我知道如果你要我载的服务器代码,并在测试中双方使用的证书。
潜在的问题可能是SSL会话(Schannel中的高速缓存)的缓存。 只有第一个请求协商SSL握手。 后续请求将使用相同的会话ID,并希望服务器接受它。 如果服务器清除会话ID,请求将失败,403错误。 要禁用本地SSL会话缓存(并迫使每个请求SSL协商),你必须打开Windows的注册表文件夹:
[HKEY_LOCAL_MACHINE] [系统] [CURRENTCONTROLSET] [控制] [SecurityProviders] [SCHANNEL]
并添加一个名为ClientCacheTime(DWORD)值为0的关键。
这个问题是这里介绍:
http://support.microsoft.com/?id=247658
您有至少两个问题的潜力......
第一...
您的客户端证书文件不能包含一个私钥,除非它使用密码进行访问。 您应该使用一个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]
})
);
第二...
你的下一个问题将是服务器端。 服务器必须允许此证书。 你有正确的逻辑,但在电线上的错误的一边,移动这条线到Web服务器处理请求。 如果不能,则必须采取以上保存到服务器的“.CER”文件并将其添加到服务器计算机的信任列表:
ServicePointManager.ServerCertificateValidationCallback = (a,b,c,d) => true;
你需要一个证书密码? 如果是这样,则在构造它的字段。
X509Certificate cert = new X509Certificate(PathToCertificate,YourPassword);