I am attempting to use the RestSharp library to call a REST API. RestSharp uses HttpWebRequest under the covers. Calling the API works fine when using HTTP, however I need to use the HTTPS protocol when calling the API. The API server has a valid certificate that is trusted in all browsers.
When I attempt to use the HTTPS protocol to call the API, I get a TlsException with the message
Invalid certificate received from server. Error code: 0xffffffff800b010a
The solutions I have found to solve this problem involve setting a callback on ServicePointManager.ServerCertificateValidationCallback that always returns true. This is unacceptable in production as it introduces a security vulnerability.
I understand that Mono doesn’t have any root certificates contained in it’s Trust Store by default (FAQ: Security | Mono). It is possible to import the root certificates used by Mozilla products into the Trust Store by using the mozroots command, however it seems that the implementation of Mono that ships with Unity is missing this tool. Can Unity actually use certificates contained in a Trust Store?
“… Use the mozroots.exe tool (included in Mono 1.1.10 and later) to download and install all Mozilla’s root certificates (i.e. the ones used in Firefox and other Mozilla’s software). It’s easier than finding a specific root but it’s also less granular to make a decision about which one(s) you install or not. …”
There are two reasons why certificate is rejected:
X509ChainStatusFlags.UntrustedRoot
X509ChainStatusFlags.RevocationStatusUnknown
Using the mozroots.exe tool to import CA list to Mono/Unity Trust Store fixes first reason.
I found a solution that works for me:
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.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 = chainIsValid;
}
}
}
}
return isOk;
}
I have the same issue however when I want to import CA’s using the mozroot.exe I always get a null reference exception:
Downloading from 'http://anduin.linuxfromscratch.org/BLFS/other/certdata.txt'...
Importing certificates into user store...
Error: System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
bei Mono.Security.X509.X509Certificate.get_Hash()
bei Mono.Security.X509.X509CertificateCollection.IndexOf(X509Certificate value)
bei Mono.Tools.MozRoots.Process()
bei Mono.Tools.MozRoots.Main(String[] args)
When I try to build the X509Chain I also don’t get X509ChainStatusFlags.UntrustedRoot instead I get RevocationStatusUnknown and OfflineRevocation.
Is there anyone who managed to get a propper SSL certificate validation including Chain-of-trust verification, hostname verification and CRL verification?