编写者:郑昀@UltraPower
 关键字:HttpWebRequest, 
SSL,X509Certificate
 dotNet  Framwork 1.1 
 
编写时间:2005-3-29 
 WSE 2.0 SP3 
 
目的:
对于用HttpWebRequest加载证书请求远端https服务器时,发生的
“基础连接已经关闭: 无法与远程服务器建立信任关系。”/
“The underlying connection was closed. Could not establish a secure SSL/TLS connection”错误,我们可以用如下方式解决。
重现:
使用以下代码,你就可以得到这个错误“基础连接已经关闭: 无法与远程服务器建立信任关系”:
using System;
using System.Text;
using System.Net;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Web.Services2.Security;
using Microsoft.Web.Services2.Security.Tokens;
using Microsoft.Web.Services2.Security.X509;
static void Main(string[] args)
{
StringBuilder sb=new StringBuilder();
string _strToRequest = "send";
try
{
//POST请求开始
byte[] bt=Encoding.Default.GetBytes("send");
HttpWebRequest Req=(HttpWebRequest)System.Net.WebRequest.Create("https://202.108.CCC.XXX:Port//");
Req.KeepAlive=true;
//Req.Timeout=60000;
Req.ContentType="text/xml";
Req.ContentLength=_strToRequest.Length;
Req.Method="POST";
X509CertificateStore store = X509CertificateStore.CurrentUserStore( X509CertificateStore.MyStore );
store.OpenRead();
//读取证书的keyid
Microsoft.Web.Services2.Security.X509.X509CertificateCollection certs =
store.FindCertificateByKeyIdentifier( Convert.FromBase64String( "CXv+xZ78zI3qWHGJ6Wh9BF6B23A=" ) );
X509SecurityToken token = null;
if (certs.Count > 0)
{
// 得到证书存储区的第1个人证书
token = new X509SecurityToken( ((Microsoft.Web.Services2.Security.X509.X509Certificate) certs[0]) );
}
if(token != null)
Req.ClientCertificates.Add(token.Certificate);
Req.KeepAlive=true;
Stream ReqStream=Req.GetRequestStream();
ReqStream.Write(bt,0,bt.Length);
ReqStream.Close();
//得到响应
HttpWebResponse res=(HttpWebResponse)Req.GetResponse();
StreamReader sr=new StreamReader(res.GetResponseStream(),Encoding.Default);
sb.Append(sr.ReadToEnd());
res.Close();
sr.Close();
}
catch(Exception ex)
{
sb.Remove(0,sb.Length);
sb.Append("\n");
                sb.Append("
                sb.Append("
sb.Append("\n");
}
Console.WriteLine(sb.ToString());
Console.Read();
}
 
原因: 
在“http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/cpguide/html/cpconhostingremoteobjectsininternetinformationservicesiis.asp”提到:
“
证书标识特定的计算机,该计算机的名称位于证书的公共名称中。但是,很容易就会更改计算机的名称或使用客户端配置文件中的“localhost”,这会在客户端和服务器证书中的公共名称之间造成不匹配的情况。在 .NET Framework 1.0 版中,这一不匹配的情况将被忽略,并且将在服务器上引发调用。
从 .NET Framework 1.1 版开始,这一不匹配的情况会引发以下异常:“System.Net.WebException:基础连接已经关闭:无法与远程服务器建立信任关系”。如果您无法配置远程处理客户端以使用证书公共名称,则可以使用客户端应用程序配置文件中的以下设置重写这一不匹配的情况。
   
                  checkCertificateName="true"          />               若要以编程方式使客户端忽略证书名称不匹配,客户端必须创建一个特定类的实例,如果 certificateProblem 值为 0x800c010f,该类将实现 ICertificatePolicy 接口并实现 CheckValidationResult 方法以返回 true。然后,您必须将该对象注册到 System.Net.ServicePointManager 对象,方法是将该对象传递到 ServicePointManager.CertificatePolicy 属性。”    解决之道:    但是用它列出的代码还是不对,我们改为CheckValidationResult无条件返回true即可。如下所示声明一个TrustAllCertificatePolicy类:        public class TrustAllCertificatePolicy : System.Net.ICertificatePolicy            {                public TrustAllCertificatePolicy()                {}                    public bool CheckValidationResult(ServicePoint sp,                    System.Security.Cryptography.X509Certificates.X509Certificate cert,                    WebRequest req, int problem)                {                    return true;                }            }    System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();    即可。    这样,代码就可以顺利和https服务器建立SSL通道了。    编写者:郑昀@UltraPower   I have read your articles on CSDN before. # re: [C#]用HttpWebRequest加载证书建立SSL通道时发生异常的解决办法     # re: [C#]用HttpWebRequest加载证书建立SSL通道时发生异常的解决办法     至于key id ,是通过WSE .20中的X.509 证书工具查看的.  //POST请求开始  Req.Method="POST";  System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();  Stream ReqStream=Req.GetRequestStream();  internal class TrustAllCertificatePolicy:ICertificatePolicy  bobomail@citiz.net  # re: [C#]用HttpWebRequest加载证书建立SSL通道时发生异常的解决办法     对应的错误  这个不知道怎么解决阿  # re: [C#]用HttpWebRequest加载证书建立SSL通道时发生异常的解决办法     也就是说,你的CA Cert并没有被对方所信任。你不觉得很奇怪吗?你装对方站点提供的证书了吗?  1:询问对方是否需要证书?  2:你的时钟和对方的时间是否差距在5分钟之内?  3:这种现象如果换一台测试机器,是否依然出现呢? 
 
然后,在请求之前加上 
 
Feedback
# re: [C#]用HttpWebRequest加载证书建立SSL通道时发生异常的解决办法    
2005-04-16 01:41 by lonelystranger 
Nice! 
# re: [C#]用HttpWebRequest加载证书建立SSL通道时发生异常的解决办法    
2005-07-28 14:18 by caravarn 
TrustAllCertificatePolicy 这个类具体怎么用啊,我还是 
不明白我的 msn :bobomail@citiz.net 
2005-07-28 20:19 by bobomail 
store.FindCertificateByKeyIdentifier( Convert.FromBase64String( "CXv+xZ78zI3qWHGJ6Wh9BF6B23A=" ) ); 
这句话 里的CXv+xZ78zI3qWHGJ6Wh9BF6B23A=" 就是证书号码 
这个在程序里怎么制定 
很急啊 msn : bobomail@citiz.net 
2005-07-29 00:11 by 让变化成为计划的一部分 
Hi, 
如果你链接的服务器并不要求你用证书,虽然你要走https,其实读取证书的keyid 是不需要的。后来我们就没有取,直接做请求,只要有 
System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy(); 
这句话,就可以了。 
发件人: ZhengYun 
收件人: 'bobomail@citiz.net' 
主题: 代码如下所示 
using Microsoft.Web.Services2.Security; 
using Microsoft.Web.Services2.Security.Tokens; 
using Microsoft.Web.Services2.Security.X509; 
byte[] bt=Encoding.Default.GetBytes(_strToRequest); 
HttpWebRequest Req=(HttpWebRequest)System.Net.WebRequest.Create(_Url); 
Req.KeepAlive=true; 
Req.ContentType="txt/xml"; 
....................... 
{ 
public TrustAllCertificatePolicy() 
{ 
// 
// TODO: 在此处添加构造函数逻辑 
// 
} 
public bool CheckValidationResult(ServicePoint sp,System.Security.Cryptography.X509Certificates.X509Certificate cert,System.Net.WebRequest req, int problem) 
{ 
return true;// 这是最关键的,返回true,告诉客户端忽略证书名称不匹配! 
} 
} 
# re: [C#]用HttpWebRequest加载证书建立SSL通道时发生异常的解决办法    
2005-08-01 15:04 by caravarn 
我请求的服务器是用java 开发 System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy(); 调试中也 return true 
但还是提示连接失败? 
这是原因呢? 
2005-08-17 11:14 by caravarn 
返回的错误 
Problem code 0x800B0109 
Problem code 0x800B0101 
Problem code 0x800B010F 
Problem code 0x00000000 
public enum CertificateProblem : long 
{ 
CertEXPIRED = 0x800B0101, 
CertVALIDITYPERIODNESTING = 0x800B0102, 
CertROLE = 0x800B0103, 
CertPATHLENCONST = 0x800B0104, 
CertCRITICAL = 0x800B0105, 
CertPURPOSE = 0x800B0106, 
CertISSUERCHAINING = 0x800B0107, 
CertMALFORMED = 0x800B0108, 
CertUNTRUSTEDROOT = 0x800B0109, 
CertCHAINING = 0x800B010A, 
CertREVOKED = 0x800B010C, 
CertUNTRUSTEDTESTROOT = 0x800B010D, 
CertREVOCATION_FAILURE = 0x800B010E, 
CertCN_NO_MATCH = 0x800B010F, 
CertWRONG_USAGE = 0x800B0110, 
CertUNTRUSTEDCA = 0x800B0112 
} 
2005-08-18 09:45 by 让变化成为计划的一部分 
错误号:0x800B0109的意思是: 
A certificate chain processed, but terminated in a root certificate which is 
not trusted by the trust provider 
至于0x800b0101的意思是 :A required certificate is not within its validity period when 
verifying against the current system clock or the timestamp in the signed 
file. 
那么请你确定几点: 
相关文章
- C# textbox窗口自动补全输入_编程资料分享
 - c#使用web的UrlEncode/UrlDecode 方法
 - C#调用其他目录dll 配置文件操作
 - C#混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集。
 - utf-8 网页不显示+utf-8网页乱码的通用解决方法
 - C#入门教程之ListBox控件使用方法
 - Oralce 调用Delphi写DLL去访问C# WebService的问题
 - C#中动态数组(ArrayList )应用实例子(三层代码:数据访问层,业务层,页面层)
 - c#调用API显示内部局域网内的主机
 - c# DataGrid 使用 小tip (1)
 

