public static bool ValidateServerCertificate(
object sender,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
return true;
Debug.Log("Certificate error: " + sslPolicyErrors);
return false;
// in my main function:
System.Net.Security.RemoteCertificateValidationCallback orgCallback = ServicePointManager.ServerCertificateValidationCallback;
var aesCrypto = new System.Security.Cryptography.AesCryptoServiceProvider();
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(ValidateServerCertificate);
ServicePointManager.Expect100Continue = true;
WebRequest wr = WebRequest.Create(url);
Stream stream = wr.GetResponse ().GetResponseStream ();
Debug.Log (new StreamReader (stream).ReadToEnd ());
catch (WebException we)
Debug.Log ("status: "+we.Status);
if (we != null we.InnerException != null)
if (we.InnerException.Message == "The authentication or decryption has failed.")
sslCheckState = SSLCheckState.NOT_OK;
finally
ServicePointManager.ServerCertificateValidationCallback = orgCallback;
Calling the base url I’ve sent you, PolicyErrors contains “RemoteCertificateChainErrors” … (output at line 10)
If I call for example a test site with an expired SSL certificate like “https://testssl-expire.disig.sk/”, PolicyErrors contains “RemoteCertificateNameMismath, RemoteCertificateChainErrors”. So at least there is some difference…
Ok… What you want to look at in your hander is:
chain.ChainStatus
This will return an array… you want to look at the “Status” and “Status Information” properties. There are two errors being returned:
RevocationStatusUnknown
UntrustedRoot
There may be something wrong with the cert… or it’s not able to get the revocation status from the certificate authority for some reason.
Ok I think I may have a solution for you. Remove the certificate validation handler for now and just go back to your webrequest in your Try/Catch block. I did some additional testing. I first created a site with a self-signed cert to verify and I got the same error. Then I changed the validation method to just return true and it worked perfectly, so it does seem to be a certificate validation error but I don’t think the certificate is the problem because I replaced your URL with “https://www.google.com” and “https://www.microsoft.com” and I got the exact same error.
I think the error is misleading and is actually caused by a policy restriction. First, change your code to this so you can see the actual exceptions being thrown:
WebRequest wr = WebRequest.Create("your-url-here");
Stream stream = wr.GetResponse().GetResponseStream();
Debug.Log("Success");
Debug.Log(new StreamReader(stream).ReadToEnd());
catch(WebException we)
var ex = we as Exception;
while (ex != null)
Debug.Log(ex.ToString());
ex = ex.InnerException;
You’ll see three exceptions going back to the Invalid Server Certificate exception. I think this is because there is no crossdomain.xml file on your host. Create a crossdomain.xml file with the following. Easiest is to create it in Notepad++ and made sure it is UTF-8 encoded by clicking the Encoding menu and selecting “Encoding in UTF-8”. It grants access to port 443 (the SSL Port).
<?xml version="1.0" ?>
<cross-domain-policy>
<allow-access-from domain="*" to-ports="443" />
</cross-domain-policy>
Problem solved! After your suggestion with Crossdomain.xml I talked to the person responsible for the server where that file should have been copied. He did not want to go that way (security concerns) and we found a way that finally everything works fine. Now I will ship the certificates in my app, and at program start a X509Certificate2Collection takes the certificates in a static variable.
When the ssl callback method is called, a new chain is build by that collection and checked.
in ValidateServerCertificate:
X509Chain tempChain = new X509Chain();
tempChain.ChainPolicy.RevocationMode = chain.ChainPolicy.RevocationMode;
X509Certificate2Collection cert2Collection = tempChain.ChainPolicy.ExtraStore;
cert2Collection.AddRange(myStaticX509Collection);
return = tempChain.Build(new X509Certificate2(certificate));
First why doesn’t this work on my Android? Is it a Unity Pro thing?
Second thanks for all your posts!, I was able to get something working for myself
But it does not work on my Android Device, is this a Unity Pro function? I only have the free version thanks! Here’s the code, what I had to do was that is a little different from the previous examples is include a client cert… Jogo I couldn’t get Validate Cert to return true so I don’t know what I’m doing wrong there so in my example it just always returns true… so I’m still trying to figure that out but I am able to get my response back so I’m like 65% happy
using UnityEngine;
using System.Collections;
using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Xml;
public class newhttptest : MonoBehaviour
string s = "not set";
// Use this for initialization
void Start ()
X509Certificate2 adminClient = new X509Certificate2 ("Assets/Scripts/adminClient.p12", "xxxxxx");
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback (ValidateServerCertificate);
try {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create ("https://xxxx/rest/user-message");
request.AuthenticationLevel = AuthenticationLevel.MutualAuthRequested;
request.ClientCertificates.Add (adminClient);
HttpWebResponse response = (HttpWebResponse)request.GetResponse ();
//XmlDocument xmlDoc = new XmlDocument();
//xmlDoc.Load(response.GetResponseStream());
Debug.Log(new StreamReader(response.GetResponseStream()).ReadToEnd());
Debug.Log ("Success");
s = "yippy!";
} catch (WebException we) {
var ex = we as Exception;
s = "fail";
while (ex != null) {
Debug.Log (ex.ToString ());
ex = ex.InnerException;
public static bool ValidateServerCertificate (
object sender,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
return true;
void OnGUI(){
GUI.Label (new Rect (0, 0, 100, 100), s);
if (GUI.Button (new Rect (20, 20, 100, 100), s)) {
Application.Quit();
// Update is called once per frame
void Update ()
When I run it on Android nothing appears to happen, I set the button in the scene to get text “yippy!” or “fail” depending on the results of the try/catch statement but it keeps its default value “not set”. I’m using Unity 4.5.0f6. The scene is empty except for the main camera and a cube with the script attached. I also made sure that the manifest file has
is there another permission I need since I’m also using a file to create my x.509 certs?
and I also added some comments around this line
s = "making cert";
X509Certificate2 adminClient = new X509Certificate2 ("Assets/Scripts/adminClient.p12", "xxxxx");
s = "cert created";
And what I found was is that the Android gets to the “making cert” line and quits so it’s a good bet that this is where the error is thrown. So at least now I know where the problem is; so now I just need to figure out a fix. Let me know if you have an idea 
Hi Dustin!
So after I tried everything … putting it the resources trying Application.persistentDataPath and storing the .p12 with a txt and bytes extension and then trying Resources.Load… nothing worked! Then finally I just used a www call to down load the .p12 from a server and then store it in Application.persistentDataPath and guess what? It worked!!! I’ll post all the details later today
for now I’m taking a break! Thanks for your help with this 
As promised here’s what my final solution looks like
using UnityEngine;
using System.Collections;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Xml;
public class RestCalls : MonoBehaviour
X509Certificate2 adminClient;
string clientCertPath="";
static string baseUrl = "https://"someurl"/rest/";
void Start ()
clientCertPath = Application.persistentDataPath + "/adminClient.p12";
StartCoroutine (GetCert ());
private IEnumerator GetCert ()
if (File.Exists (clientCertPath)) {
print ("I have the file");
MakeRestCall();
} else {
WWW download = new WWW ("http://"pathtocert"/adminClient.p12");
yield return download;
if (download.error != null) {
print ("Error downloading: " + download.error);
} else {
File.WriteAllBytes (clientCertPath, download.bytes);
public XmlDocument MakeRestCall()
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback (ValidateServerCertificate);
adminClient = new X509Certificate2 (clientCertPath, "xxxxx");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create (baseUrl + "user-message");
request.AuthenticationLevel = AuthenticationLevel.MutualAuthRequested;
request.ClientCertificates.Add (adminClient);
HttpWebResponse response = (HttpWebResponse)request.GetResponse ();
XmlDocument xmlDoc = new XmlDocument ();
xmlDoc.Load (response.GetResponseStream ());
return xmlDoc;
public static bool ValidateServerCertificate (
object sender,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
//TODO Make this more secure
return true;
I using #18 same code for SSL validation, but i am getting below error on line no. 48 in #18 code, in editor. I am loading my .p12 certificate file from persistent storage. Please help
IOException: BeginWrite failure
System.Net.Sockets.NetworkStream.BeginWrite (System.Byte[] buffer, Int32 offset, Int32 size, System.AsyncCallback callback, System.Object state)
Mono.Security.Protocol.Tls.RecordProtocol.BeginSendRecord (ContentType contentType, System.Byte[] recordData, System.AsyncCallback callback, System.Object state)
Mono.Security.Protocol.Tls.RecordProtocol.SendRecord (ContentType contentType, System.Byte[] recordData)
Mono.Security.Protocol.Tls.RecordProtocol.SendAlert (Mono.Security.Protocol.Tls.Alert alert)
Mono.Security.Protocol.Tls.RecordProtocol.SendAlert (AlertDescription description)
Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (IAsyncResult asyncResult)
Rethrow as WebException: Error getting response stream (Write: BeginWrite failure): SendFailure
System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult)
System.Net.HttpWebRequest.GetResponse ()
How to validate SSL certificates when using HttpWebRequest
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) {
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;
return isOk;