對於用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("<?XML version=\"1.0\" encoding=\"gb2312\"?>\n");
sb.Append("<slia ver=\"1.0.0\">\n");
sb.Append("<result resid=\"501\">"+ex.Message+"</result>\n");
sb.Append("</slia>\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:基礎連接已經關閉:無法與遠程服務器建立信任關系”。如果您無法配置遠程處理客戶端以使用證書公共名稱,則可以使用客戶端應用程序配置文件中的以下設置重寫這一不匹配的情況。
<system.Net>
<settings>
<servicePointManager
checkCertificateName="true"
/>
</settings>
</system.Net>
若要以編程方式使客戶端忽略證書名稱不匹配,客戶端必須創建一個特定類的實例,如果 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
Feedback
# re: [C#]用HttpWebRequest加載證書建立SSL通道時發生異常的解決辦法
2005-04-16 01:41 by lonelystranger
Nice!
I have read your articles on CSDN before.
# re: [C#]用HttpWebRequest加載證書建立SSL通道時發生異常的解決辦法
2005-07-28 14:18 by caravarn
TrustAllCertificatePolicy 這個類具體怎麼用啊,我還是
不明白我的 msn :[email protected]
# re: [C#]用HttpWebRequest加載證書建立SSL通道時發生異常的解決辦法
2005-07-28 20:19 by bobomail
store.FindCertificateByKeyIdentifIEr( Convert.FromBase64String( "CXv+xZ78zI3qWHGJ6Wh9BF6B23A=" ) );
這句話 裡的CXv+xZ78zI3qWHGJ6Wh9BF6B23A=" 就是證書號碼
這個在程序裡怎麼制定
很急啊 msn : [email protected]
# re: [C#]用HttpWebRequest加載證書建立SSL通道時發生異常的解決辦法
2005-07-29 00:11 by 讓變化成為計劃的一部分
Hi,
如果你鏈接的服務器並不要求你用證書,雖然你要走https,其實讀取證書的keyid 是不需要的。後來我們就沒有取,直接做請求,只要有
System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
這句話,就可以了。
至於key id ,是通過WSE .20中的X.509 證書工具查看的.
發件人: ZhengYun
收件人: '[email protected]'
主題: 代碼如下所示
using Microsoft.Web.Services2.Security;
using Microsoft.Web.Services2.Security.Tokens;
using Microsoft.Web.Services2.Security.X509;
//POST請求開始
byte[] bt=Encoding.Default.GetBytes(_strToRequest);
HttpWebRequest Req=(HttpWebRequest)System.Net.WebRequest.Create(_Url);
Req.KeepAlive=true;
Req.ContentType="txt/XML";
Req.Method="POST";
System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
Stream ReqStream=Req.GetRequestStream();
.......................
internal class TrustAllCertificatePolicy:ICertificatePolicy
{
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
但還是提示連接失敗?
這是原因呢?
# re: [C#]用HttpWebRequest加載證書建立SSL通道時發生異常的解決辦法
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
}
這個不知道怎麼解決阿
# re: [C#]用HttpWebRequest加載證書建立SSL通道時發生異常的解決辦法
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
也就是說,你的CA Cert並沒有被對方所信任。你不覺得很奇怪嗎?你裝對方站點提供的證書了嗎?
至於0x800b0101的意思是 :A required certificate is not within its validity period when
verifying against the current system clock or the timestamp in the signed
file.
那麼請你確定幾點:
1:詢問對方是否需要證書?
2:你的時鐘和對方的時間是否差距在5分鐘之內?
3:這種現象如果換一台測試機器,是否依然出現呢?