强制HttpWebRequest发送客户端证书

我有一个p12证书,我以这种方式加载它:

X509Certificate2 certificate = new X509Certificate2(certName, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); 

它是正确加载的,实际上如果我做了certificate.PrivateKey.ToXmlString(true); 它返回一个完整的xml而没有错误。 但如果我这样做:

 try { X509Chain chain = new X509Chain(); var chainBuilt = chain.Build(certificate); Console.WriteLine("Chain building status: "+ chainBuilt); if (chainBuilt == false) foreach (X509ChainStatus chainStatus in chain.ChainStatus) Console.WriteLine("Chain error: "+ chainStatus.Status); } catch (Exception ex) { Console.WriteLine(ex); } 

它写道:

 Chain building status: False Chain error: RevocationStatusUnknown Chain error: OfflineRevocation 

所以当我这样做时:

  ServicePointManager.CheckCertificateRevocationList = false; ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true; ServicePointManager.Expect100Continue = true; Console.WriteLine("connessione a:" + host); HttpWebRequest req = (HttpWebRequest)WebRequest.Create(host); req.PreAuthenticate = true; req.AllowAutoRedirect = true; req.ClientCertificates.Add(certificate); req.Method = "POST"; req.ContentType = "application/x-www-form-urlencoded"; string postData = "login-form-type=cert"; byte[] postBytes = Encoding.UTF8.GetBytes(postData); req.ContentLength = postBytes.Length; Stream postStream = req.GetRequestStream(); postStream.Write(postBytes, 0, postBytes.Length); postStream.Flush(); postStream.Close(); WebResponse resp = req.GetResponse(); 

服务器说证书没有发送/有效。

我的问题是:

  • 即使链构建错误,我怎么能发送证书?
  • 还有另一个类发布证书,在发送之前不检查证书validation吗?

非常感谢。 安东尼

我解决了这个问题,重点是P12文件(作为PFX)包含多于1个证书,因此必须以这种方式加载:

 X509Certificate2Collection certificates = new X509Certificate2Collection(); certificates.Import(certName, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet); 

并以这种方式添加到HttpWebRequest: request.ClientCertificates = certificates;

谢谢大家的支持。

完整的示例代码

 string host = @"https://localhost/"; string certName = @"C:\temp\cert.pfx"; string password = @"password"; try { X509Certificate2Collection certificates = new X509Certificate2Collection(); certificates.Import(certName, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet); ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true; HttpWebRequest req = (HttpWebRequest)WebRequest.Create(host); req.AllowAutoRedirect = true; req.ClientCertificates = certificates; req.Method = "POST"; req.ContentType = "application/x-www-form-urlencoded"; string postData = "login-form-type=cert"; byte[] postBytes = Encoding.UTF8.GetBytes(postData); req.ContentLength = postBytes.Length; Stream postStream = req.GetRequestStream(); postStream.Write(postBytes, 0, postBytes.Length); postStream.Flush(); postStream.Close(); WebResponse resp = req.GetResponse(); Stream stream = resp.GetResponseStream(); using (StreamReader reader = new StreamReader(stream)) { string line = reader.ReadLine(); while (line != null) { Console.WriteLine(line); line = reader.ReadLine(); } } stream.Close(); } catch(Exception e) { Console.WriteLine(e); } 

问题是您将私钥安装到计算机存储区,对于不在本地系统帐户下运行或具有显式私钥权限的进程,通常不允许将其用于客户端身份validation。 您需要在当前用户存储中安装密钥:

 X509Certificate2 certificate = new X509Certificate2(certName, password, X509KeyStorageFlags.UserKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); 

我创建了一个命令行程序,使用代码的修改版本和pfx证书,其中包含从IE导出的私钥,我可以对安全网站进行身份validation并检索受保护的页面:

 string host = @"https://localhost/"; string certName = @"C:\temp\cert.pfx"; string password = @"password"; try { X509Certificate2 certificate = new X509Certificate2(certName, password); ServicePointManager.CheckCertificateRevocationList = false; ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true; ServicePointManager.Expect100Continue = true; HttpWebRequest req = (HttpWebRequest)WebRequest.Create(host); req.PreAuthenticate = true; req.AllowAutoRedirect = true; req.ClientCertificates.Add(certificate); req.Method = "POST"; req.ContentType = "application/x-www-form-urlencoded"; string postData = "login-form-type=cert"; byte[] postBytes = Encoding.UTF8.GetBytes(postData); req.ContentLength = postBytes.Length; Stream postStream = req.GetRequestStream(); postStream.Write(postBytes, 0, postBytes.Length); postStream.Flush(); postStream.Close(); WebResponse resp = req.GetResponse(); Stream stream = resp.GetResponseStream(); using (StreamReader reader = new StreamReader(stream)) { string line = reader.ReadLine(); while (line != null) { Console.WriteLine(line); line = reader.ReadLine(); } } stream.Close(); } catch(Exception e) { Console.WriteLine(e); }