Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSL Instructions (Curl error 60: Cert verify failed: UNITYTLS_X509VERIFY_FLAG_UNKNOWN_ERROR) #197

Open
Nikit-Kalach opened this issue Dec 16, 2021 · 16 comments

Comments

@Nikit-Kalach
Copy link

Nikit-Kalach commented Dec 16, 2021

Hello everyone,

I'm writing the code that should get some info from the server on the virtual machine with self-signed certificate. I found your package and it's wonderfull! I've searched for few hours, but never found any documentation about the SSL certificates...
Without the SSL Certificate validation i get this error: Curl error 60: Cert verify failed: UNITYTLS_X509VERIFY_FLAG_UNKNOWN_ERROR
Also I tried to find any answer for resolving this problem but never found one so my code would work properly,
Please help,

With best wishes,
Nikita Kalachev

For the code, I just wrote this:

`using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEditor;
using Models;
using Proyecto26;
using Proyecto26.Common;
using RSG;
using RSG.Exceptions;
using RSG.Promises;

public class RESTCPack : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Debug.Log("I'm alive! Hope it'll work!");
}

// Update is called once per frame
void Update()
{
    RestClient.Get("https://someurl/").Then(res =>
    {
       Debug.Log("Response" + res.Text + "Ok");
    }); 
}

/*
public class CertificateHandlerPublicKey : CertificateHandler
{

    // Encoded RSAPublicKey
    private static string PUB_KEY = "somepublickey";
    protected override bool ValidateCertificate(byte[] certificateData)
    {
        X509Certificate2 certificate = new X509Certificate2(certificateData);
        string pk = certificate.GetPublicKeyString();
        Debug.Log(pk);
        if (pk.ToLower().Equals(PUB_KEY.ToLower()))
            return true;
        return false;
    }
}

*/

}`

@jdnichollsc
Copy link
Member

Hello mate, hope you're doing well
Can you send me any example using UnityWebRequest directly? I don't have experience using that, but with a code sample I can help you to create the code for this asset! <3

Best,
Juan

@Nikit-Kalach
Copy link
Author

Hi, thank you for your attention, wait a sec...
Adding the UnityWebRequest code:

As you can see, I tried to add some code that I thought could help me, but it didn't work :(

Hope you can help me

With best wishes,
Nikita Kalachev

`public class REST : MonoBehaviour
{
public Text text;

// Start is called before the first frame update
void Start()
{
    StartCoroutine(getUnityWebRequest());
}

// Update is called once per frame
void Update()
{

}

public IEnumerator getUnityWebRequest()
{
    

    UnityWebRequest restreq = UnityWebRequest.Get("myURL");
    restreq.certificateHandler = new CertificateHandlerPublicKey();

    // var cert = new ForceAcceptAll(); variant of correcting the PUB KEY

    // www.certificateHandler = cert; variant of correcting the PUB KEY

    yield return restreq.SendWebRequest();

    // cert?.Dispose(); variant of correcting the PUB KEY

    if (restreq.isNetworkError /* || www.HttpError */) //www.result == www.Result.ConnectionError
    {
        Debug.Log(restreq.error);
    }
    else
    {
        //show result as text
        Debug.Log(restreq.downloadHandler.text);
    }
    
}

// CertificateHandler connects the certificate methods

public class CertificateHandlerPublicKey : CertificateHandler 
{
    //public Text textpk;

    // Encoded RSAPublicKey
    private static string PUB_KEY = "mypublickey";
    protected override bool ValidateCertificate(byte[] certificateData)
    {
        X509Certificate2 certificate = new X509Certificate2(certificateData);
        string pk = certificate.GetPublicKeyString();
        Debug.Log(pk);
        if (pk.ToLower().Equals(PUB_KEY.ToLower()))
            return true;
        return false;
    }

   /* restreq.ServerCertificateValidationCallback += CertificateValidationCallback;

    public bool CertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        return certificate.Equals(cert);
    } */
} 

/*
public class ForceAcceptAll : CertificateHandler
{
    protected override bool ValidateCertificate(byte[] certificateData)
    {
        return true;
    }
}
*/

}`

@jdnichollsc
Copy link
Member

jdnichollsc commented Dec 17, 2021

Hey mate, thanks for sharing!

Try this example and please let me know

RestClient.Get(new RequestHelper {
  Uri = "https://myapi.com",
  CertificateHandler = new YourCertificateHandler()
}).Then(response => {

});

@Nikit-Kalach
Copy link
Author

Unfortunately it doesn't work :( Here is my code for now:

`void Update()
{
RestClient.Get(new RequestHelper
{
Uri = "Uri",
CertificateHandler = new CertificateHandlerPublicKey()
}).Then(response => {

    });
}


public class CertificateHandlerPublicKey : CertificateHandler
{

    // Encoded RSAPublicKey
    private static string PUB_KEY = "mypubkey";
    protected override bool ValidateCertificate(byte[] certificateData)
    {
        X509Certificate2 certificate = new X509Certificate2(certificateData);
        string pk = certificate.GetPublicKeyString();
        Debug.Log(pk);
        if (pk.ToLower().Equals(PUB_KEY.ToLower()))
            return true;
        return false;
    }
}`

@jdnichollsc
Copy link
Member

jdnichollsc commented Dec 17, 2021

Hello mate, can you share logs and give me more context about your REST API please?

@Nikit-Kalach
Copy link
Author

Hello, thank you for helping me, I'm using Unity3D, VisualStudio 2019 to be honest, I'm pretty new to the scripting so I can understand not very much... But this is what I'm getting as an error:
Curl error 60: Cert verify failed: UNITYTLS_X509VERIFY_FLAG_UNKNOWN_ERROR

Also this is my code:

`using System;
using System.Net;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEditor;
using Proyecto26;
using RSG;
using RSG.Exceptions;

public class REST : MonoBehaviour
{
[SerializeField] private string url;

private void Awake()
{
    RestClient.Get(new RequestHelper
    {
        Uri = url,
        CertificateHandler = new MyCertificateHandler()
    }).Then(response => {

    });
}

public class MyCertificateHandler : CertificateHandler
{ 
    private static string PUB_KEY = "mypublickeystring";
    protected override bool ValidateCertificate(byte[] certificateData)
    {
        X509Certificate2 certificate = new X509Certificate2(certificateData);
        string pk = certificate.GetPublicKeyString();
        // на случай потребности в pub_key use: Debug.Log(pk)
        if (pk.Equals(PUB_KEY))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

}`

As for the context - I'm trying to connect to the server, which is protected by the Certificate.pfx and as I understood in this code I should first send the request, that contains the GET thing (forgot what it's name) and Verification of servers certificate.

What I've done:
I created the server on virtual machine and protected it with the self-signed certificate (wich was created is IIS),
Then I added it to my host machine and added the certificate to Trusted root (as i figured it by googling)
And it still throws the error.. I just don't understand why is that so?
The PublicKey matches 100%, but as I understood Unity even don't get there, it stops on the GET and then throw an ERROR)

@Nikit-Kalach
Copy link
Author

Also as i understood, I can't call the ValidateCertificate's value (of true or false) that's why, maybe, it throws an error?

@jdnichollsc
Copy link
Member

Hi, thank you for your attention, wait a sec... Adding the UnityWebRequest code:

As you can see, I tried to add some code that I thought could help me, but it didn't work :(

Hope you can help me

With best wishes, Nikita Kalachev

`public class REST : MonoBehaviour { public Text text;

// Start is called before the first frame update
void Start()
{
    StartCoroutine(getUnityWebRequest());
}

// Update is called once per frame
void Update()
{

}

public IEnumerator getUnityWebRequest()
{
    

    UnityWebRequest restreq = UnityWebRequest.Get("myURL");
    restreq.certificateHandler = new CertificateHandlerPublicKey();

    // var cert = new ForceAcceptAll(); variant of correcting the PUB KEY

    // www.certificateHandler = cert; variant of correcting the PUB KEY

    yield return restreq.SendWebRequest();

    // cert?.Dispose(); variant of correcting the PUB KEY

    if (restreq.isNetworkError /* || www.HttpError */) //www.result == www.Result.ConnectionError
    {
        Debug.Log(restreq.error);
    }
    else
    {
        //show result as text
        Debug.Log(restreq.downloadHandler.text);
    }
    
}

// CertificateHandler connects the certificate methods

public class CertificateHandlerPublicKey : CertificateHandler 
{
    //public Text textpk;

    // Encoded RSAPublicKey
    private static string PUB_KEY = "mypublickey";
    protected override bool ValidateCertificate(byte[] certificateData)
    {
        X509Certificate2 certificate = new X509Certificate2(certificateData);
        string pk = certificate.GetPublicKeyString();
        Debug.Log(pk);
        if (pk.ToLower().Equals(PUB_KEY.ToLower()))
            return true;
        return false;
    }

   /* restreq.ServerCertificateValidationCallback += CertificateValidationCallback;

    public bool CertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        return certificate.Equals(cert);
    } */
} 

/*
public class ForceAcceptAll : CertificateHandler
{
    protected override bool ValidateCertificate(byte[] certificateData)
    {
        return true;
    }
}
*/

}`

Hello mate, sorry for the delay

Are you getting the same error using ForceAcceptAll with RestClient?

Happy holidays! <3

@Nikit-Kalach
Copy link
Author

Unfortunately, it doesn't help at all :( So Now I'm triying to figure out how to setup the certificate on the server correctly, I guess the issue is on the server's side.
I can give you more details: I'm trying to connect the Unity3d to WinCC Server, via the REST API. I found the video, link would be bellow:
https://youtu.be/mLwLL-cQAwA
I hope it wount be quilified as an advertisment, cause it is not. And with Postman (if I disable checking for the SSL-Certificate it can read the values clearly) But if I try to disable the checking on the Unity's side (as the ForceAcceptAll) It simply doesn't work... It's writing me the next ERROR:

image

Could you help me please? Also I would be greaful if you could help me with the Certificate, because the security is pretty vital for the project.

Thank you very much and happy holidays :)

@AbdullahNarsun
Copy link

I am having the same issue. Does anyone able to fixes this? @jdnichollsc @Nikit-Kalach
Here are my code snippets
image
image
image

NOTE: API's endpoints are working fine in postman

@maifeeulasad
Copy link
Collaborator

@AbdullahNarsun please provide a minimal reproducible example as a GitHub repository. Please include these:

  • Unity project
  • Backend (if any)
  • Instruction to run this project (if it has some unique methodology)

I'm available for a few days; I guess I will try my best to fix it. Thanks.

@AbdullahNarsun
Copy link

AbdullahNarsun commented Jan 9, 2023

@maifeeulasad >

Thanks for the reply. Sorry, my project got sensitive information/data due to which i wont be able to share it with you. One thing i can do is to share some extra code snippets with you. If that will help you to understand better, than please let me know.
Thank You

@maifeeulasad
Copy link
Collaborator

@AbdullahNarsun in case you missed this keyword minimal reproducible example.

Good read:

@AbdullahNarsun
Copy link

@maifeeulasad Please have a look, here is the project with example
https://github.com/AbdullahNarsun/SSL-Certificate-Error

I also send you an invitation, but later on i made it public. Simply run in unity and click the only button visible to you.

@maifeeulasad
Copy link
Collaborator

@AbdullahNarsun,

I have seen your code and tried resolving it with CertificateHandler, but it doesn't work. Let me tell you why. Unity doesn't support TLS 1.3. But your server is using TLS 1.3.

tls 1.2 support unity

chilliswap using tls 1.3

Another interesting thing is jsonplaceholder.typicode.com are also using TLS 1.3, but I can call some REST from their server.

At first, I thought this was some issue on our end. But then I wrote a script without our RestClient; now I can guarantee that, you need to downgrade to TLS 1.2, or configure your server.

Here is the script, if you are interested:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using UnityEngine;
using UnityEngine;
using UnityEngine.Networking;

// Based on https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#.Net
class AcceptAllCertificatesSignedWithASpecificKeyPublicKey : CertificateHandler
{
    // Encoded RSAPublicKey
    // private static string
    //     PUB_KEY =
    //         "00 04 FD ED 3C 8D 85 62 4D E0 67 50 82 B6 41 D2" +
    //         "CB 22 18 47 C5 59 67 24 0A 6F AA E6 FD 3F 2F 85" +
    //         "0D C7 29 58 CC 32 34 3D 5E 6B E8 38 B9 75 5C A8" +
    //         "72 5B B9 16 5E 27 43 A6 C8 A6 2A 14 EF A1 9B 3C" +
    //         "B4 D0";
    protected override bool ValidateCertificate(byte[] certificateData)
    {
        Debug
            .Log("*********                ********************            ********************      pong");
        return true;
        // X509Certificate2 certificate =
        //     new X509Certificate2(certificateData);
        // string pk = certificate.GetPublicKeyString();
        // if (pk.Equals(PUB_KEY)) return true;

        // // Bad dog
        // return false;
    }
}

public class Raw : MonoBehaviour
{
    IEnumerator ping()
    {
        // var url = "https://jsonplaceholder.typicode.com/todos";
        var url = "https://game-api.chilliswap.org/api/users/getProfile";
        var KEY =
            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYyNmE1Mjk2ZmQ0Yzg1MTk5MzVhZGM2OCIsInB1YmxpY0FkZHJlc3MiOiIweDBjNzI5YzFmODFlOGE1Y2UxNzYwN2UwMDMzODFkOGQ0NDhlYTU1ZGYiLCJpYXQiOjE2NTExMzY4OTl9.Iw_n8y0TEkIDrHFhW3iJWwAmmOP5ohtzufRlodU-tX4";

        var www = UnityWebRequest.Get(url);

        www.SetRequestHeader("x-access-token", KEY);

        www.certificateHandler =
            new AcceptAllCertificatesSignedWithASpecificKeyPublicKey();

        var operation = www.SendWebRequest();

        while (!www.isDone)
        {
            yield return null;
        }

        var jsonResponse = www.downloadHandler.text;

        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.LogError("-------------error-----------");
        }

        Debug.Log (jsonResponse);
    }

    void Start()
    {
        StartCoroutine(ping());
    }
}

Sorry, I couldn't be any help. You may create an ticket on Unity forum or their bug reporting center

Ref:

@AbdullahNarsun
Copy link

@maifeeulasad Thank you for the help, I also tried it with default web request (UnityWebRequest) and found the same result. Will create an issue on unity forum shortly.
Appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants