我需要相信应用程序中的一些自签名证书,所以我覆盖了这样的验证回调:
ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback;
...
public static bool MyRemoteCertificateValidationCallback(
Object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
if (IsAprrovedByMyApplication(sender, certificate)) // <-- no matter what the check here is
return true;
else
return false; // <-- here I'd like to call the default Windwos handler rather than returning 'false'
}
但是当出现一些策略错误,并且我连接的站点未被应用程序批准时,将抛出异常。 这里的问题是它与标准Windows行为不同。
考虑以下网站:https://www.dscoduc.com/
它的证书有一个未知的发行者,因此不受信任。我已经将它与MMC一起添加到Local Copmuter的受信任人(它是Windows 7)。
如果我在不覆盖证书验证回调的情况下运行此代码:
HttpWebRequest http = (HttpWebRequest)HttpWebRequest.Create("https://www.dscoduc.com/");
using (WebResponse resp = http.GetResponse())
{
using (StreamReader sr = new StreamReader(resp.GetResponseStream()))
{
string htmlpage = sr.ReadToEnd();
}
}
它成功连接。 这意味着Windows默认验证程序决定信任此证书。
但是一旦我覆盖ServerCertificateValidationCallback,就会使用 SslPolicyErrors.RemoteCertificateChainErrors 调用我的回调。 并且链包含一个状态为 X509ChainStatusFlags.PartialChain 的元素(实际上我希望在这里不会收到任何错误,因为当前的证书应该是可信的)
此网站未包含在我的受信任列表中,并且不希望从我的回调中返回“true”。 但是我不想也不返回'false',否则我会得到一个异常:“远程证书根据验证程序无效”,这显然不是https://www.dscoduc.com/所期望的,因为它被添加到受信任的人存储,并且在未覆盖证书回调时由Windows批准。 所以我希望Windows采用此站点的默认验证程序。我不想自己查看Windows Trusted存储并浏览所有链元素,因为它已经(并且希望在Windows中)正确实现。
换句话说,我需要明确信任用户认可的网站(存储在他的设置中的某个位置),并为所有其他网站调用默认的认证检查。
ServicePointManager.ServerCertificateValidationCallback的默认值为null,因此以后没有“默认”回调供我调用。 我应该如何称呼这个“默认”证书处理程序?
由于
答案 0 :(得分:6)
从你的回调中走出链条比你想象的要困难。
查看http://msdn.microsoft.com/en-us/library/dd633677(v=exchg.80).aspx
如果证书是自签名的,那么该示例中的代码会检查证书链是否可用,如果是,请相信它。您可以将其调整为接受PartialChain
或同样接受if (status.Status == X509ChainStatusFlags.PartialChain ||
(certificate.Subject == certificate.Issuer &&
status.Status == X509ChainStatusFlags.UntrustedRoot)
{
// Certificates with a broken chain and
// self-signed certificates with an untrusted root are valid.
continue;
}
else if (status.Status != X509ChainStatusFlags.NoError)
{
// If there are any other errors in the certificate chain,
// the certificate is invalid, so the method returns false.
return false;
}
。你想要做这样的事情:
Subject
或者,检查private static bool CertificateValidationCallBack(
object sender,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
return certificate.Subject.Contains(".dsoduc.com");
}
属性:
{{1}}
答案 1 :(得分:3)
这样的事可能有用。请注意,X509CertificateValidator允许您选择是否在验证中包含“受信任的人”存储。
private static bool CertificateValidationCallBack(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
// Your custom check here...
if (isYourSpecialCase)
{
return true;
}
// If it is not your special case then revert to default checks...
// Convert the certificate to a X509Certificate2
var certificate2 = certificate as X509Certificate2 ?? new X509Certificate2(certificate);
try
{
// Choose the type of certificate validation you want
X509CertificateValidator.PeerOrChainTrust.Validate(certificate2);
//X509CertificateValidator.ChainTrust.Validate(certificate2);
}
catch
{
return false;
}
// Sender is always either a WebReqest or a hostname string
var request = sender as WebRequest;
string requestHostname = request != null ? request.RequestUri.Host : (string)sender;
// Get the hostname from the certificate
string certHostname = certificate2.GetNameInfo(X509NameType.DnsName, false);
return requestHostname.Equals(certHostname, StringComparison.InvariantCultureIgnoreCase);
}
答案 2 :(得分:0)
@ pete.c的解决方案似乎正常工作(已检查不同情况)
但是,如果仍然不确定X509CertificateValidator是否以相同的方式进行验证,则可以通过反射来运行默认回调:
private static object s_defaultCallback;
private static MethodInfo s_defaultCallbackInvoker;
...
// Get the original callback using reflection
PropertyInfo[] pis = typeof (ServicePointManager).GetProperties(BindingFlags.Static | BindingFlags.NonPublic);
foreach (var pi in pis)
{
if (pi.Name == "CertPolicyValidationCallback")
{
s_defaultCallback = pi.GetValue(null, null);
s_defaultCallbackInvoker = s_defaultCallback.GetType().GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
break;
}
}
...
private static bool CertificateValidationCallBack(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
// Your custom check here...
if (isYourSpecialCase)
{
return true;
}
// Default Windows behavior
WebRequest req = sender as WebRequest;
if (req == null)
return false;
ServicePoint sp = ServicePointManager.FindServicePoint(req.RequestUri);
string host = req.RequestUri.Host;
object [] parameters = new object[]
{
host,
sp,
certificate,
req,
chain,
sslPolicyErrors
};
return (bool)s_defaultCallbackInvoker.Invoke(s_defaultCallback, parameters);
}