使用不在证书库中的客户端证书

我正在尝试使用我的客户端证书对WebService进行身份validation,但是,由于某些原因(我解释),我不想从商店加载证书,而是从光盘读取它。

下列:

// 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服务(客户端)有时会调用webservice(服务器),并且在未指定的时间后服务’忘记’我的证书并且没有对服务器进行授权,没有明显的原因)

什么类型的文件是PathToCertificate? 如果它只是一个.cer文件,它将不包含证书的私钥,并且尝试将该证书用于SSL / TLS将失败。

但是,如果您的PKCS7或PKCS12文件包含证书的公钥和私钥,则您的代码将起作用(如果私钥有密码,您可能需要使用带密码的重载)。

为了测试这个,我去了http://www.mono-project.com/UsingClientCertificatesWithXSP并按照这些说明创建了我的client.p12文件。 我还使用HttpListener创建了一个简单的HTTPS服务器进行测试。

然后我将以下程序编译成’client.exe’并运行如下:

  client.exe https:/// client.p12 password 

其中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 ()); } } 

如果您希望我上传服务器代码和测试两侧使用的证书,请告诉我。

潜在的问题可能是SSL会话的缓存(Schannel缓存)。 只有第一个请求才能协商SSL握手。 后续请求将使用相同的会话ID,并希望服务器接受它。 如果服务器清除SessionId,请求将失败,并显示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 >. "-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);