- Home /
How to accept self signed certificate
I am trying to access a rest API hosted on one of my company's servers. However, as it is a dev server the SSL certificate is self signed and so Unity refuses to accept the connection. I've tried to follow this answer in particular. Which gave me this code :
void GetRequest(string uri)
{
ServicePointManager.ServerCertificateValidationCallback = TrustCertificate;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
Debug.Log("responseFromServer=" + responseFromServer);
}
However when trying to connect to the server I got this error :
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied.
I must add that I only have access to the .crt certificate Firefox got me when navigating to the server and I do not know how to add it to Mono properly (tried with certmgr but I'm not sure it worked with only the .crt) I'm on Windows 10.
So how can I make Unity to accept my certificate ?
It seems that the error I got is due to the response stream was not received at the time the code is trying to access it with the StreamReader.
Thus I tried with this solution, using BeginGetResponse ins$$anonymous$$d of GetResponse :
void GetRequest(string uri)
{
ServicePoint$$anonymous$$anager.ServerCertificateValidationCallback = TrustCertificate;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.BeginGetResponse(ResponseCallback, request);
}
private void ResponseCallback(IAsyncResult result)
{
Debug.Log("Response CB");
HttpWebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result) as HttpWebResponse;
Debug.Log("1");
Stream dataStream = response.GetResponseStream();
Debug.Log("2");
StreamReader reader = new StreamReader(dataStream);
Debug.Log("3");
string responseFromServer = reader.ReadToEnd();
Debug.Log("4");
Debug.Log("responseFromServer=" + responseFromServer);
}
This time the code stalls after Debug.Log("Response CB") and I have no idea why it does
Answer by goddatr · Mar 22, 2018 at 12:45 PM
Ok, I finally solved it :
First thing to do was to switch to Unity beta 2018.1. There I have the UnityWebRequest.certificateHandler This allows to set up custom certificate validation. one last thing to do is to create an object extending CertificateHandler to manage Certificate validation. (See here in Unity beta documentation)
Here is the code :
MyMonoBehaviour :
IEnumerator GetRequest(string uri){
UnityWebRequest request = UnityWebRequest.Get(uri);
request.certificateHandler = new AcceptAllCertificatesSignedWithASpecificKeyPublicKey();
yield return request.SendWebRequest ();
if (request.isNetworkError)
{
Debug.Log("Something went wrong, and returned error: " + request.error);
}
else
{
// Show results as text
Debug.Log(request.downloadHandler.text);
}
}
AcceptAllCertificatesSignedWithASpecificKeyPublicKey :
using UnityEngine.Networking;
using System.Security.Cryptography.X509Certificates;
using UnityEngine;
// Based on https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#.Net
class AcceptAllCertificatesSignedWithASpecificKeyPublicKey : CertificateHandler
{
// Encoded RSAPublicKey
private static string PUB_KEY = "mypublickey";
protected override bool ValidateCertificate(byte[] certificateData)
{
X509Certificate2 certificate = new X509Certificate2(certificateData);
string pk = certificate.GetPublicKeyString();
if (pk.ToLower().Equals(PUB_KEY.ToLower()))
return true;
return false;
}
}
if can't switch to Unity beta 2018.1 how can i solve my project depend unity 2017.2.1
Well, I didn't succeed with 2017.2 but you maybe can use the .NET HttpWebRequest method as it seems to work for some people.
If anyone finds this and is having trouble with it, I changed the final 'return false' to 'return true' and it works. Probably not the most secure way? But in my case it's running on a private network so no issues there.
That change makes it trust all certificates, so your connection is no longer secure
Well Self-signed certificates are not really secure either when you want to secure connections to unknow / untrusted peers. $$anonymous$$an-in-the-middle attacks are perfectly possible with self signed certificates since you can not verify you actually talk to the right person. Self signed certificates only make sense if the two peers know each other and know the certificate of the other party. For usual web traffic most web browsers would reject any connections to servers with self signed certificates. Anybody can create a self signed certificate. Validating that certificate only tells you that the certificate is valid, nothing more. It's generally better to aquire an actual signed certificate. LetsEncrypt lets you create a signed certificate for free.