Search Unity

Resolved UnityWebRequest report an error : SSL CA certificate error

Discussion in 'Multiplayer' started by QianXiYa, Jan 23, 2019.

  1. QianXiYa

    QianXiYa

    Joined:
    Nov 1, 2017
    Posts:
    27
    Hi,
    when Android API >= 28, Google does not allow plaintext HTTP requests, but if I change the request to HTTPS, an SSL CA certificate error will occur,But the website certificate is without a problem

    Is there a solution?
     
  2. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    This error means the the website uses a certificate that is issued by an untrusted issuer.
    Unity takes trusted issuers from device store, so this error means you have to either install updates on your phone and expect the issuer to be added or manually add the issuers certificate (usually not recommended, since not being trusted by OS usually means the issuer is not trustforthy).
     
  3. QianXiYa

    QianXiYa

    Joined:
    Nov 1, 2017
    Posts:
    27
    Unity cannot configure the publisher certificate itself
     
  4. QianXiYa

    QianXiYa

    Joined:
    Nov 1, 2017
    Posts:
    27
    Can't you call the certificates configured in the aar package?
     
  5. doctorpangloss

    doctorpangloss

    Joined:
    Feb 20, 2013
    Posts:
    270
    You can try using System.Net.WebRequest and the following snippet instead:

    Code (CSharp):
    1. ServicePointManager.ServerCertificateValidationCallback +=
    2.     (sender, certificate, chain, sslPolicyErrors) => true;
    But I think you should just get a valid web certificate, it's worth learning how to use ACME/LetsEncrypt.
     
    Muratunlu0 and andrew_pearce_ like this.
  6. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    The certificate handler on UnityWebRequest does the same for UWR.
     
  7. doctorpangloss

    doctorpangloss

    Joined:
    Feb 20, 2013
    Posts:
    270
    Ah, maybe I'm used to iOS development where the underlying web request library is libcurl. I didn't realize that it was engineered to respect some obscure .Net certificate handling scheme!
     
  8. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Does anyone have a proper solution for this one?
     
    mentorgame1 likes this.
  9. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    For those who's interested in a workaround, create a certificate handler that accepts all certs (what I've found in another thread):
    Code (CSharp):
    1. public class ForceAcceptAll : CertificateHandler
    2. {
    3.     protected override bool ValidateCertificate(byte[] certificateData)
    4.     {
    5.         return true;
    6.     }
    7. }
    Then, feed it as a field to the UnityWebRequest, like:
    Code (CSharp):
    1. var cert = new ForceAcceptAll();
    2.  
    3. // www is a UnityWebRequest
    4. www.certificateHandler = cert;
    5.  
    6. // Send
    7.  
    8. cert?.Dispose();
    Note that unfortunately its not working while re-using single certificate, that's why you need to create a new instance (and dispose it later). But its not as big GC as web request itself, so it shouldn't be too much for you.

    Edit: Also, be aware that this is potentially a GP developer policy breach, if used incorrectly (and found by the Google, your build might get rejected).

    So use it with caution, and do not send vital / secret / personal information via those requests.
     
    Last edited: Aug 5, 2019
  10. MrsPiggy

    MrsPiggy

    Joined:
    Jun 13, 2018
    Posts:
    154
    @xVergilx hmmm I wouldn't know about that. It's a workaround for sure, but it's like saying instead of locking the door I will just put a chair against the door knob and hope for the best. In other words, if there's a security issue with the certificate this workaround is simply gambling with your player's data security. I'd rather check what's wrong with the certificate and maybe replace it.
     
  11. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    I doubt we'll be able to replace an Amazon certificate (because that's where bucket from which we load asset bundles are) validation on some chineese devices (because that's what user base uses unfortunately).

    I don't know any other workaround for this case.
    We're using that request only to download bundles. No personal data involved. Its a public readonly access bucket.

    Actually HTTP would've worked just fine (so its kinda works like that?).
    Also, I don't think you can really inject executable code via MITM or alike to the asset bundle that can be executed, AFAIK.


    This issue is definitely beyond mortal realm of peasant dwarf devs (like me).
    Just trusting an OS to figure out what's safe and what's not doesn't work.

    Just FYI, Accessing that bucket from the devices browser is not a problem, however, Unity's SSL validation fails miserably.

    But Unity haven't provided a proper, known to me, fix yet, as of (2018.4~).

    Edit: Also added a warning about it.
     
    Last edited: Aug 5, 2019
    MrsPiggy likes this.
  12. MrsPiggy

    MrsPiggy

    Joined:
    Jun 13, 2018
    Posts:
    154
    fair enough, my comment was taking for granted you had control over the ssl certificate. But is it also the case for the OP?
     
  13. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    If you are concerned about the security, you should validate the certificate manually in certificate handler.
     
    sami1592 and xVergilx like this.
  14. Akhil1195

    Akhil1195

    Joined:
    Aug 19, 2019
    Posts:
    3
    unity WWW Error: HTTP/1.1 404 Not Found
    UnityEngine.Debug:Log(Object)
    <GetStatusData>d__10:MoveNext() (at Assets/NewScripts/RegistrationControllerScript.cs:64)
    UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)
    showing this error please help me to recover this issue;
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Networking;
    3. using System.Security.Cryptography.X509Certificates;
    4.  
    5. public class AcceptAllCertificatesSignedWithASpecificKeyPublicKey : CertificateHandler
    6. {
    7.  
    8.     // Encoded RSAPublicKey
    9.     private static string PUB_KEY = "3082010A0282010100AD3E1BBBF82BE073DC5756F57452DB15F1FE3AD0B62066EC91CCCFD7F3C4D6596C076A6152B16E47217C2B0C4143066176F8E3730E1D43D2DD9F7E01E5B88DC1AED991E8ED8FE42ACFB92E5F4E61F86807E31082F4006DB4413323793CC85C91C2E26E3F084F783311F722006AF4A57DA73214EE3014B45E5D048C33732A803BA027DD0EFA1A29F05A7D6DACD01C9968DF2F5C4A7D4145E3F3C118E55615F956AEC5CD2C3A753E08E5E136400D6D396E69AD682D59D49FDDA848B648FCB673CE6421602C2195CDC469D546B90E4F50C8862BE4FC5E3DCF3BB3B47855577173A912A43AA171498C7656DBEF441A456A5D68DDD8CC00533D2CBBCB20BC92B7BE150203010001";
    10.      protected override bool ValidateCertificate(byte[] certificateData)
    11.      {
    12.        X509Certificate2 certificate = new X509Certificate2(certificateData);
    13.        string pk = certificate.GetPublicKeyString();
    14.         Debug.Log("Key :"+pk);
    15.        if (pk.Equals(PUB_KEY))
    16.             return true;
    17.         return false;
    18.      }
    19.    /* public static implicit operator CertificateHandler(AcceptAllCertificatesSignedWithASpecificKeyPublicKey v)
    20.     {
    21.         throw new NotImplementedException();
    22.     }*/
    23. }
    24.  
     
  15. sami1592

    sami1592

    Joined:
    Sep 18, 2013
    Posts:
    57
    How can we do that? Can you please give me an example? That would help a lot.

    For my case :
    1. I have a 'custom' certificate (a
      .pfx
      file) with a password (no public string afaik)
    2. In order to access the contents from Chrome, first I got to install the certificate with the said password.
    3. Then after accessing the page, I have to use a username and password to get to to the content.
    4. So, two layers.
    5. So that was from Chrome. Now, I would like to do this from Unity.
    6. With Unity, this examples were helpful, but I am stuck with the certificate part.
    I hope this info will help you help me.

    PS : I am new to networking/certificate type stuff, so please bear with me :)
     
  16. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
  17. sami1592

    sami1592

    Joined:
    Sep 18, 2013
    Posts:
    57
    Hey thanks for the quick reply. Much appreciated.

    Excuse me, I am gonna ask some real noob questions now. Hopefully this will server others who are as clueless as me in this matter.

    1. This ValidateCertifacate example was the first thing that came across. As far as I understand, I create a class like in the example, override the
      ValidateCertificate
      method and set it to
      UnityWebRequest.certificateHandler
    2. In this examlpe, they do not deal with private key(or password). But
      X509Certificate2
      has functionality for checking it, so I guess that is no problem.
    3. From the same link, it says `Certificate data in PEM or DER format. If certificate data contains multiple certificates, the first one is the leaf certificate`. I am guessing this is what you mean by extracting data ("You'll have to extract your certificate data"). I am not sure how to do that. My certificate file is a
      .pfx
      one.
    4. I found the public key by going to "Manage user certificates" on Windows. It is pkcs#12 format, generated and signed by openssl.
    5. I have found this where they are using
      WWW
      class. I am not sure if it matters or not which class I use (WWW or UnityWebrequest) offers more flexibility or is there a reason to chose one over the other.
    I hope you will be able to help me regarding this topic.
     
    FixItFelix likes this.
  18. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
  19. sami1592

    sami1592

    Joined:
    Sep 18, 2013
    Posts:
    57
    1. If this function
      protected override bool ValidateCertificate(byte[] certificateData)
      from
      CertificateHandler
      is to receive the certificate data in PEM or DER format, then I have to first read the certificate file(
      .pfx
      fille in my case) first, convert it and inform my
      UnityWebRequest
      object about it. But in my case, where I want to get data from a webpage, I do not see an option to read and set the certificate data to
      UnityWebRequest
      . It seems so silly, I feel like I am missing something that is very obvious. The only code I have managed to find is this webpage, and they are using PUT, which if I understand correctly is for uploading data. Either, resources are very scarce in this topic, or I am using the wrong search terms.
    2. openssl
      is not available in windows by default. So does it mean, every developer in my team have to install it in order to work with it? And, when made into executables, I am assuming the user does not have to worry about that, correct?

    If anyone can spare some time to do a detailed answer, it would mean a lot to me.
     
  20. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    If you've setup your website using that certificate, you can use your web browser to extract the certificate (well, at least Firefox allows me to save certificate in PEM format).
     
    sami1592 likes this.
  21. sami1592

    sami1592

    Joined:
    Sep 18, 2013
    Posts:
    57
    So you are suggesting to work with a .PEM certificate file to begin with, so that we don't have to convert it Unity? Okay, I will talk to my team about it.

    Can you help with my other question as well?

    If this function
    protected override bool ValidateCertificate(byte[] certificateData)
    from
    CertificateHandler
    is to receive the certificate data in PEM or DER format, then I have to first read the certificate file(
    .pfx
    fille in my case) first, convert it and inform my
    UnityWebRequest
    object about it. But in my case, where I want to get data from a webpage, I do not see an option to read and set the certificate data to
    UnityWebRequest
    . It seems so silly, I feel like I am missing something that is very obvious. The only code I have managed to find is this webpage, and they are using PUT, which if I understand correctly is for uploading data. Either, resources are very scarce in this topic, or I am using the wrong search terms. Here is the code from that webpage with translations for convenience -
    Code (CSharp):
    1. using System.Collections;
    2. using System.Security.Cryptography.X509Certificates;
    3. using System.Text;
    4. using UnityEngine;
    5. using UnityEngine.Networking;
    6.  
    7. public class NetTEST : MonoBehaviour
    8. {
    9.     private string pubkey;
    10.     class CertPublicKey : CertificateHandler
    11.     {
    12.         public string PUB_KEY;
    13.  
    14.         // Encoded RSAPublicKey
    15.         protected override bool ValidateCertificate(byte[] certificateData)
    16.         {
    17.             X509Certificate2 certificate = new X509Certificate2(certificateData);
    18.             string pk = certificate.GetPublicKeyString();
    19.  
    20.             if (pk.ToLower().Equals(PUB_KEY.ToLower()))
    21.                 return true;
    22.             else
    23.                 return false;
    24.         }
    25.     }
    26.  
    27.     private void Start()
    28.     {
    29.         // Generate PublicKey for authentication
    30.         TextAsset tx = Resources.Load<TextAsset>("certificateFile");
    31.         byte[] by = Encoding.UTF8.GetBytes(tx.ToString());
    32.  
    33.         X509Certificate2 certificate = new X509Certificate2(by);
    34.         pubkey = certificate.GetPublicKeyString();
    35.  
    36.         StartCoroutine(Post("https://url", by));
    37.     }
    38.  
    39.     private IEnumerator Post(string url, byte[] data)
    40.     {
    41.         // We need to send data in bytes. UnityWebRequest.POST is string only. Put it in Put and then change it to POST.
    42.  
    43.         UnityWebRequest request = UnityWebRequest.Put(url, data);
    44.         {
    45.             request.method = "POST";
    46.             request.certificateHandler = new CertPublicKey{ PUB_KEY = pubkey };
    47.             //request.SetRequestHeader("Content-Type", "application/json");
    48.  
    49.             yield return request.SendWebRequest();
    50.  
    51.             if (request.isNetworkError)
    52.             {
    53.                 Debug.Log(request.error + " / " + request.responseCode);
    54.             }
    55.             else
    56.             {
    57.                 Debug.Log(request.downloadHandler.text);
    58.             }
    59.         }
    60.     }
    61. }
     
  22. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    What you need is certificate in your script. If you have it in PEM format, you can put it inside script as string, then create X509Certificate2 object from it and put that object in your certificate handler. Then it's a matter of comparing whether certificate you've got as a parameter is the same as the one you have in your handler.
     
  23. sami1592

    sami1592

    Joined:
    Sep 18, 2013
    Posts:
    57
    What you need is certificate in your script. If you have it in PEM format, you can put it inside script as string, then create X509Certificate2 object from it

    Understood this part

    and put that object(X509Certificate2 object) in your certificate handler. Then it's a matter of comparing

    This part I did not understand. This is my understanding so far -
    1. The comparison happens in the function
      ValidateCertificate(byte[] certificateData)
      .
    2. This function gets the certificate data in its parameter
      certificateData
      .
    3. As far as I understand it gets called by the
      UnityWebRequest[ICODE]
      [/ICODE] object. So, I need to tell this UnityWebRequest object about this certificate data, so it calls
      ValidateCertificate(byte[] certificateData)
      with the right argument.
    if this is correct, then I do not see how putting X509Certificate2 object in
    CertificateHandler
    class(inherited) will help
     
  24. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    UnityWebRequest calls ValidateCertificate() passing in the certificate it received from server. The purpose of ValidateCertificate() is to validate it and return true or false, saying whether it's trusted. What you have to do is to compare the received certificate against the one you expect.
    So in the end you have expected X509Certificate2 in certificate handler and other X509Certificate2 you created from argument, now the task is to compare them. You can try using .Equals(), but I'm not entirely sure here, maybe just comparing public keys is enough. Reference:
    https://docs.microsoft.com/en-us/do...ertificates.x509certificate2?view=netcore-3.1
     
  25. djkpA

    djkpA

    Joined:
    Mar 28, 2016
    Posts:
    14
    In my standalone game build, I am getting the error Curl error 51: Cert verify failed: UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED and API calls are failing with error code as 0.

    I am not getting this error in the editor, I am only getting this error in build.

    I have disabled the SSL pinning that is used in my game and after that, all API's are working fine without any errors.
    1. Code (CSharp):
      1.     void addCertificatHeader(UnityWebRequest unityWebRequest)
      2.     {
      3.         CertificateHandler certificateHandler = new AcceptAllCertificatesSignedWithASpecificKeyPublicKey();
      4.         unityWebRequest.certificateHandler = certificateHandler;
      5.     }
      6.  
      7.     // Based on https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#.Net
      8.     class AcceptAllCertificatesSignedWithASpecificKeyPublicKey : CertificateHandler
      9.     {
      10.  
      11.         protected override bool ValidateCertificate(byte[] certificateData)
      12.         {
      13.             X509Certificate2 certificate = new X509Certificate2(certificateData);
      14.             string pk = certificate.GetPublicKeyString();
      15.             pk = pk.ToLower();
      16.             if (pk.Equals(getPublicKey()))
      17.             {
      18.                 return true;
      19.             }
      20.  
      21.             // Bad dog
      22.             return false;
      23.         }
      24.     }
    The build is used to work fine, but suddenly after some point, this error is coming.

    Unity Editor Version: 2019.3.0f6
    Build Platform: Standalone

    Any helps folks?
     
  26. adi_unity515

    adi_unity515

    Joined:
    Oct 30, 2019
    Posts:
    1
    I am having the same issue - some % of our users get "SSL CA certificate error" when trying to call some APIs. The domain is google cloud domain (appspot.com, not a private one, so I dont think there's a chance any of the certificates are not validated. This has started only when we upgraded Android api from 27 (android 8.1) to 29 (android 10).
    I can see google changed some security stuff from android 9 around that area (web certificates, http cleartext...). Do we need to do anyting on unity side to fully support android 9+? If not, why would unity fail a google cloud certificate?

    Thanks.
     
  27. Raistlin2015

    Raistlin2015

    Joined:
    Apr 4, 2015
    Posts:
    27
  28. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    It is called when secure connection is being established at the point where certificate trust has to be determined. It will not be called if there is a failure before that, such as unsupported TLS version (Unity supports up to 1.2).
    Also note, that this method is called on arbitrary thread, not Unity main thread.
     
    Raistlin2015 likes this.
  29. Raistlin2015

    Raistlin2015

    Joined:
    Apr 4, 2015
    Posts:
    27
    I found my problem. I had not set the environment variables on my server. I have a Node.js api for storing specific, non mechanic game state and user data. i.e. what I don't want to accomplish in PUN2 / Mirror. I had a conditional to set the protocol http / https depending on weather the process.env.MY_VAR was "dev" or "prod". Thank You for the help.
     
  30. mentalup

    mentalup

    Joined:
    Dec 14, 2017
    Posts:
    7
    Is there any update on this issue? We are using 2021.2.7f1 and seeing this error a lot on failed download logs. These are coming from file downloads (assetbundle, json, etc) from Microsoft Azure CDN servers. We are now using a custom DNS, using what Azure CDN gives to us.
     
  31. thef006

    thef006

    Joined:
    Jul 26, 2017
    Posts:
    2
    I'm experiencing a similar issue when trying to communicate with an API hosted on Azure. Requests work in the editor, but on device (HoloLens 2, UWP platform) I always get the 'SSL CA certificate error' message. The interesting part is that this message only appears when the build is done with 2020.3.25f1 or 2020.3.27f1. The same requests on the same device work with version 2019.4.32f1...

    I've tried adding a custom certificate handler and this does not help with the issue. The handler is invoked though, this I've confirmed with debugging...
     
  32. TheJavierD

    TheJavierD

    Joined:
    Jan 6, 2017
    Posts:
    51
    I can also confirm that https networking is completely broken in UWP builds for Hololens 2.

    It worked just fine in 2020.3.18f and broke completely when I updated to 2020.3.25f
    If it helps you thef006, you can use the .18f build
     
    thef006 likes this.
  33. thef006

    thef006

    Joined:
    Jul 26, 2017
    Posts:
    2
    Just a little bit of time before reading this comment I saw that Unity 2020.3.28f1 was released. Reading the patch notes I saw a TLS related issue and decided to try to do a build with the new version.

    While the description of the issue is different, it seems that it also solved the issue with the 'SSL CA certificate error' message: https://issuetracker.unity3d.com/is...hen-uwp-build-configuration-is-set-to-release

    @TheJavierD if you are able to upgrade to 28f1, it might help with your situation too :)
     
  34. TheJavierD

    TheJavierD

    Joined:
    Jan 6, 2017
    Posts:
    51
    Yes you are right, it's fixed in 2020.3.28f such great news!
     
  35. Sayoj

    Sayoj

    Joined:
    Oct 22, 2020
    Posts:
    4
    I've still got this problem with the newest version (2020.3.32f1) and 2021.2.17
    even after setting the certificateHandler to always return true

    I am using Node and the certifcate is from LetsEncrypt
     
  36. mentalup

    mentalup

    Joined:
    Dec 14, 2017
    Posts:
    7
    This is weird that when our clients move from cellular to wifi, they can connect and download the required files to open the app but it does not work on some cellular companies' lines and throws this SSL CA Certificate error. We are having this problem while downloading from Azure CDNs but we tried everything that we can, tested using Front Door for content delivering, tested returning true always to certificateHandler, tested other HTTP libraries such as BestHTTP/2 but no solution.

    Using: 2021.3.0f1
     
    Last edited: Apr 26, 2022
  37. n_saikiran

    n_saikiran

    Joined:
    Sep 1, 2016
    Posts:
    20
    @Aurimas-Cernius Does the ValidateCertificate() method get invoked for each and every WebRequest?
    For each WebRequest call, I am initializing a new WebRequest object and I am adding the CertificateHandler to the headers of the request.
    When I placed logs inside that function, the log is not printing each and every time a WebRequest is sent.

    Am I missing anything else? Shouldn't the ValidateCertificate be supposed to be invoked each time the CertificateHandler is added to the WebRequest headers?
     
  38. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    It is supposed to be called for each request.
    Note, that Unity Editor can merge identical messages together, so you see only one message and a number of times it showed up.
     
  39. n_saikiran

    n_saikiran

    Joined:
    Sep 1, 2016
    Posts:
    20
    Are you talking about the Collapse feature in the Console Window?
    If yes, it is disabled. All other identical logs are printing. Only logs placed inside ValidateCertificate() method are not printing each time
     
  40. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    Could you try the web request it with latest 2021.3?
    I don't remember when exactly we changed this specific behavior. It used to be the case where we allowed connection reuse, so you'd get a callback once per host. Later we fixed it, as it's not entirely correct to reuse connection, given that the answer to the trust question can be different.
     
  41. anthonius

    anthonius

    Joined:
    Jul 31, 2021
    Posts:
    2
    Anyone still facing this issue?
    my web is using SSL issued by Let's Encrypt with TLS version 1.2, but still SSL CA certificate error on some android devices. Any idea?
    I'm using unity 2020.3.16f1.
    Tried to use 2020.3.28f1 but got issue with missing recommended JDK, SDK & NDK.
     
  42. andrew_pearce_

    andrew_pearce_

    Joined:
    Nov 5, 2018
    Posts:
    169
    We are also using Let's Encrypt certificate and just got this error on Android 4.4 after migration to Unity 2020.3.40f. We were aware of this issue a year ago and I just came here to recall the solution. Thanks to @xVergilx!

    Code (CSharp):
    1. class AcceptAnyCertificate : CertificateHandler {
    2.   protected override bool ValidateCertificate(byte[] certificateData) => true;
    3. }
    4. UnityWebRequest www = UnityWebRequest.Post(***);
    5. #if UNITY_ANDROID && !UNITY_EDITOR
    6. var buildVersion = new AndroidJavaClass("android.os.Build$VERSION");
    7. if (buildVersion.GetStatic<int>("SDK_INT") < 21)
    8.   www.certificateHandler = new AcceptAnyCertificate();
    9. #endif

    I believe Android 4.4 is no longer supported and they will never be able to validate those new keys. So we have to accept any certificate from old devices (unless high security is key in the app).

    UPD: Just found (check Note 4) a confirmation that 4.4 only partially supports TLS 1.2 (btw, it was working fine until SDK was updated). So the solution is to downgrade TLS to 1.0 or 1.1 on a server but both of them are officially deprecated and we need to check if that could be a reason of app disapproval.

    UPD: According to this tool, all three TLS 1.0, 1.1 and 1.2 are enabled. Does not it mean that Unity should select appropriate (supported) one? The CURL library for example has an option to specify max TLS version "--tlsv1.0".
     
    Last edited: Oct 23, 2022
  43. thethanksforthegod

    thethanksforthegod

    Joined:
    Feb 18, 2020
    Posts:
    19
  44. andrew_pearce_

    andrew_pearce_

    Joined:
    Nov 5, 2018
    Posts:
    169
    @thethanksforthegod Do you use UnityWebRequest or something else? Have you tried to set certificateHandler or UnityWebRequest object? Finally, can you share the few lines of code and what exact error message are you getting?
     
  45. thethanksforthegod

    thethanksforthegod

    Joined:
    Feb 18, 2020
    Posts:
    19
    Thanks for your reply yes I tried UnityWebRequest also WebClient , HttpClient but nothing worked

    Code (CSharp):
    1. async void Start()
    2.     {
    3.         ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13;
    4.         ServicePointManager
    5.     .ServerCertificateValidationCallback +=
    6.     (sender, cert, chain, sslPolicyErrors) => true;
    7.         //StartCoroutine(GetText());
    8.  
    9.         using (WebClient wc = new WebClient())
    10.         {
    11.             var json = wc.DownloadString("https://api.wenlambo.one/meta?meta=1514");
    12.  
    13.         }
    14.  
    15.         using (var httpClient = new HttpClient())
    16.         {
    17.             ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12;
    18.             ServicePointManager
    19.         .ServerCertificateValidationCallback +=
    20.         (sender, cert, chain, sslPolicyErrors) => true;
    21.             var json = await httpClient.GetStringAsync("http://api.wenlambo.one/meta");
    22.             Debug.Log(json);
    23.             // Now parse with JSON.Net
    24.         }
    25.     }
     
  46. andrew_pearce_

    andrew_pearce_

    Joined:
    Nov 5, 2018
    Posts:
    169
    @thethanksforthegod You cannot solve the problem directly because this web site is using TSL 1.3 (you can see that here). As far as I know, Unity does not support 1.3 yet. However, there is a workaround: if you have any web hosting or better vps (you can get one for couple of bucks) which has TSL 1.3 installed, you can make a simple php script (check the attached file, make sure to remove .txt at the end) which will use curl and work as a proxy. You will request your script and it will request given link above.
     

    Attached Files:

  47. thethanksforthegod

    thethanksforthegod

    Joined:
    Feb 18, 2020
    Posts:
    19
    Great Thanks but I even used Native C# but no hope how a complete programming language can't use TLS 1.3 I checked MSDN an they say that it can support TLS 1.3
     
  48. andrew_pearce_

    andrew_pearce_

    Joined:
    Nov 5, 2018
    Posts:
    169
    I am updating the thread because we faced SSL error not only on Android 4. We have three confirmations on Android 8/10. Of course we could accept all certificates (no checking) but if Google somehow finds this, it will be a violation of their terms. Taking in an account that certificate checking requires two extra lines of code, it's better to do it legit way. BTW we also got confirmations from users that problem was resolved.
     
  49. ghare_reification

    ghare_reification

    Joined:
    Jul 5, 2019
    Posts:
    6
    QUESTION: Why does X509Certificate2.Verify() FAIL in the override of CertificateHandler.
    ValidateCertificate()
    when working with a valid certificate?

    Using Unity2019.4.36f1 + Windows10 tested in both Editor & Player
    Requesting from AWS S3 + CloudFront + Route 53

    First, without SSL.
    - I needed to assign a custom certificate handler to my UnityWebRequest. This worked as expected - the ValidateCertificate method received an invalid certificate, and when it returned true the web request worked.

    Second, SSL certificate issued by Sectigo
    - II verified my SSL certificate in Windows (just open the file and look for "This certificate is OK")
    - I verified that the AWS server setup is correct according to Qualys SSL Server Test.
    - I tried returning the result of certificate.Verify()... and this was FALSE.
    - If instead I did not assign a certificate handler, THEN the web request works... and the web request fails if I try to request data from a source that does not have an SSL certificate.
    - If I directly import my copy of the certificate from a file (while debugging the handler), the results appear to be identical, BUT Verify() fails for this certificate as well!
    - The stated reasons for the failure are "RevocationStatusUnknown" and "OfflineRevocation" which suggests that some of the Verify queries are blocked?

    CONCLUSION: There is a clear work-around: *only* override UnityWebRequest.certificateHandler when *correctly* verifying certificates is *not* necessary.

    QUESTION: Is this expected behavior? And, if so, WHY? (And also, please *please* update the documentation.)

    EDIT: Tested using X509Chain.Build:
    chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline;
    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags; // succeeds
    chain.ChainPolicy.VerificationFlags = IgnoreRevocationUnknownFlags; // | of 4 flags fails
    CONCLUSION: Attempting to configure an "offline" verification is not viable (or the flags are not doing what I expect)
     
    Last edited: Nov 23, 2022
  50. Danny9421

    Danny9421

    Joined:
    Mar 21, 2022
    Posts:
    36
    The problem with this methode is, public key is refreshed every 3 months using LetsEncrypt.
    So all of the webrequests (my whole game is based on) do not work in the time frame of the refresh, because i need to rebuild the game with the new key and upload it to Play Store.

    And if i validate it witouth checking a local public key its violation of google terms, according some people.

    So this is a real unefficient solution.

    Edit: i have checked, all of those values are also refreshed when LetsEncrypt resigns certificate:
    CertHash, RawCertData, SerialNumber, RawCertData
     
    Last edited: Dec 7, 2022