我正在制作一个简单的REST客户端,以便在我的C#应用程序中使用。在Windows上的.net它适用于http://和https://连接。在Ubuntu 10.10的单声道2.6.7(也用2.8测试,结果相同)只有http://有效。 https:// connections在request.GetResponse()方法上抛出此异常:
Unhandled Exception: System.Net.WebException: Error getting response stream (Write: The authentication or decryption has failed.): SendFailure ---> System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: Invalid certificate received from server. Error code: 0xffffffff800b010a
at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.validateCertificates (Mono.Security.X509.X509CertificateCollection certificates) [0x00000] in <filename unknown>:0
at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.ProcessAsTls1 () [0x00000] in <filename unknown>:0
at Mono.Security.Protocol.Tls.Handshake.HandshakeMessage.Process () [0x00000] in <filename unknown>:0
at (wrapper remoting-invoke-with-check) Mono.Security.Protocol.Tls.Handshake.HandshakeMessage:Process ()
at Mono.Security.Protocol.Tls.ClientRecordProtocol.ProcessHandshakeMessage (Mono.Security.Protocol.Tls.TlsStream handMsg) [0x00000] in <filename unknown>:0
at Mono.Security.Protocol.Tls.RecordProtocol.InternalReceiveRecordCallback (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0
--- End of inner exception stack trace ---
at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0
at System.Net.HttpWebRequest.GetResponse () [0x00000] in <filename unknown>:0
我一直无法找到解决此问题的方法。任何人都知道为什么会这样,以及如何解决它?
同样,这只在Mono中失败,.Net似乎没有任何建立连接的问题。
这是调用代码:
public JToken DoRequest(string path, params string[] parameters) {
if(!path.StartsWith("/")) {
path = "/" + path;
}
string fullUrl = url + path + ToQueryString(parameters);
if(DebugUrls) Console.WriteLine("Requesting: {0}", fullUrl);
WebRequest request = HttpWebRequest.CreateDefault(new Uri(fullUrl));
using(WebResponse response = request.GetResponse())
using(Stream responseStream = response.GetResponseStream()) {
return ReadResponse(responseStream);
}
}
答案 0 :(得分:47)
Unity遇到同样的问题(也使用单声道),this post帮我解决了。
在提出请求之前,只需添加以下行:
ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback;
这个方法:
public bool MyRemoteCertificateValidationCallback(System.Object sender,
X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
bool isOk = true;
// If there are errors in the certificate chain,
// look at each error to determine the cause.
if (sslPolicyErrors != SslPolicyErrors.None) {
for (int i=0; i<chain.ChainStatus.Length; i++) {
if (chain.ChainStatus[i].Status == X509ChainStatusFlags.RevocationStatusUnknown) {
continue;
}
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan (0, 1, 0);
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
bool chainIsValid = chain.Build ((X509Certificate2)certificate);
if (!chainIsValid) {
isOk = false;
break;
}
}
}
return isOk;
}
答案 1 :(得分:27)
Windows上的.NET Framework使用Windows证书存储(mmc,添加/删除管理单元,证书)来确定是否接受来自远程站点的SSL证书。 Windows附带了许多根证书和中间证书颁发机构(CA),它们会定期由Windows Update更新。因此,您的.NET代码通常会信任证书,前提是证书由证书存储区中的CA或CA的后代颁发(包括大多数信誉良好的商业CA)。
在Mono中,没有Windows证书存储区。 Mono拥有自己的商店。默认情况下,它为空(没有可信的默认CA)。您需要自己管理条目。
看看这里:
mozroots.exe点将使您的单声道安装信任Firefox在默认安装后信任的所有内容。
答案 2 :(得分:7)
在发出请求http请求之前写下此行。这应该是有效的。
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors) => { return true; });
private static bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
//Return true if the server certificate is ok
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
bool acceptCertificate = true;
string msg = "The server could not be validated for the following reason(s):\r\n";
//The server did not present a certificate
if ((sslPolicyErrors &
SslPolicyErrors.RemoteCertificateNotAvailable) == SslPolicyErrors.RemoteCertificateNotAvailable)
{
msg = msg + "\r\n -The server did not present a certificate.\r\n";
acceptCertificate = false;
}
else
{
//The certificate does not match the server name
if ((sslPolicyErrors &
SslPolicyErrors.RemoteCertificateNameMismatch) == SslPolicyErrors.RemoteCertificateNameMismatch)
{
msg = msg + "\r\n -The certificate name does not match the authenticated name.\r\n";
acceptCertificate = false;
}
//There is some other problem with the certificate
if ((sslPolicyErrors &
SslPolicyErrors.RemoteCertificateChainErrors) == SslPolicyErrors.RemoteCertificateChainErrors)
{
foreach (X509ChainStatus item in chain.ChainStatus)
{
if (item.Status != X509ChainStatusFlags.RevocationStatusUnknown &&
item.Status != X509ChainStatusFlags.OfflineRevocation)
break;
if (item.Status != X509ChainStatusFlags.NoError)
{
msg = msg + "\r\n -" + item.StatusInformation;
acceptCertificate = false;
}
}
}
}
//If Validation failed, present message box
if (acceptCertificate == false)
{
msg = msg + "\r\nDo you wish to override the security check?";
// if (MessageBox.Show(msg, "Security Alert: Server could not be validated",
// MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
acceptCertificate = true;
}
return acceptCertificate;
}
答案 3 :(得分:4)
默认情况下,Mono不信任任何证书,导入Mozilla受信任的root权限,您可以在mozroots.exe所在的单声道安装文件夹中运行mozroots --import --quiet
答案 4 :(得分:3)
我也遇到了错误。
我试过ServicePointManager.ServerCertificateValidationCallback
和ServicePointManager.CertificatePolicy
,但仍无效。
我生气。构建一个cURL包装器。这对我的玩具项目来说很好。
/// <summary>
/// For MONO ssl decryption failed
/// </summary>
public static string PostString(string url, string data)
{
Process p = null;
try
{
var psi = new ProcessStartInfo
{
FileName = "curl",
Arguments = string.Format("-k {0} --data \"{1}\"", url, data),
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = false,
};
p = Process.Start(psi);
return p.StandardOutput.ReadToEnd();
}
finally
{
if (p != null && p.HasExited == false)
p.Kill();
}
}
答案 5 :(得分:3)
我遇到了同样的问题。 当http响应抛出此异常时,我会这样做:
System.Diagnostics.Process.Start("mozroots","--import --quiet");
这会导入丢失的证书,并且异常永远不会再次发生。
答案 6 :(得分:2)
第一个答案已经说明了:除了Windows之外的任何东西上的Mono没有任何东西,所以最初它不信任任何证书。那该怎么办?
以下是一篇很好的文章,介绍了从开发人员的角度处理问题的不同方法: http://www.mono-project.com/archived/usingtrustedrootsrespectfully/
简短摘要: 你可以:
上面的链接附带了每个案例的代码示例。
答案 7 :(得分:2)
Unity的另一个解决方案是初始化ServicePointManager一次以始终接受证书。这有效,但显然不安全。
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate (object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
return true; // **** Always accept
};
答案 8 :(得分:0)
你可以在iOS Build中设置Mono TLS实现,一切都会正常工作,如下所述:http://massivepixel.co/blog/post/xamarin-studio-6-certificate-unknown(虽然Mono TLS不支持更新版本的TLS,但我还没有碰到这是一个问题的问题。)
答案 9 :(得分:0)
按照公认的答案导入证书后,我仍然遇到这个问题。
我发现support for TLS 1.2 was added in Mono 4.8.0使用Google的BoringSSL,并且我使用的Mono版本早于此版本。我更新到Mono 5.10,现在可以连接而不会收到此异常。