Skip to content
This repository has been archived by the owner on May 13, 2024. It is now read-only.

Trust anchor for certification path not found #586

Closed
hasnabbas opened this issue Nov 7, 2018 · 21 comments
Closed

Trust anchor for certification path not found #586

hasnabbas opened this issue Nov 7, 2018 · 21 comments

Comments

@hasnabbas
Copy link

hasnabbas commented Nov 7, 2018

Browsers and versions affected
Android native app

Description
All devices with my app installed on them are getting same error. Previously, I was getting the recent issue, /issues/585 (apprtc expired certificate). Now that that issue seems to be fixed, and now I am starting to get this one.

Steps to reproduce
Running the same app that worked previously

Expected results
Should initiate chat between two peers.

Actual results
Connection Error: HTTP POST to https://appr.tc/join/9f48fcc6-30e0-47f2-ba35-f6cb8da19a7b error: ja
va.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

@maxvuluy
Copy link

maxvuluy commented Nov 7, 2018

I think it's the COMODO untrusted certification on Android issue
https://support.comodo.com/index.php?/Knowledgebase/Article/View/1019/1/untrusted-certificate-error-on-android
Can anyone solve this?

@hasnabbas
Copy link
Author

Does apprtc provides any certificate files, like the ones used in this official android documentation

@maxvuluy
Copy link

maxvuluy commented Nov 7, 2018

Open https://appr.tc with a browser.
Click the lock icon, then you can see the detail of certification.
You can find the url to download the certification file somewhere (depend on browser).
I'm not sure, but I think it is.

I will try this way later.
If you tried, please let me know the result.
Thank you.

@elixiroflife4u
Copy link

+1 for this issue. I am also getting "Trust anchor for certification path not found" when attempting any kind of call from AppRTC Android demo app (approx release 63 and rel 68). The same app on same android device had worked till around October 30.

@maxvuluy
Copy link

maxvuluy commented Nov 8, 2018

The solution @HasnainAD mentioned worked.

  1. Download certification file and put in asset of android project.
  2. Run the following code to make android trust this certification.
httpsURLConnection.setSSLSocketFactory(trustCert().getSocketFactory());

private SSLContext trustCert() throws CertificateException,IOException,KeyStoreException,
	NoSuchAlgorithmException,KeyManagementException {
	AssetManager assetManager = getAssets();
	CertificateFactory cf = CertificateFactory.getInstance("X.509");
	Certificate ca = cf.generateCertificate(assetManager.open("COMODORSADomainValidationSecureServerCA.crt"));

	// Create a KeyStore containing our trusted CAs
	String keyStoreType = KeyStore.getDefaultType();
	KeyStore keyStore = KeyStore.getInstance(keyStoreType);
	keyStore.load(null, null);
	keyStore.setCertificateEntry("ca", ca);

	// Create a TrustManager that trusts the CAs in our KeyStore
	String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
	TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
	tmf.init(keyStore);

	// Create an SSLContext that uses our TrustManager
	SSLContext context = SSLContext.getInstance("TLS");
	context.init(null, tmf.getTrustManagers(), null);
	return context;
}

But I think it's just a compromise solution for those who cannot wait.
The ultimate way is the server need to correct it to make certification work on android.

@devedgarKim
Copy link

The solution @HasnainAD mentioned worked.

  1. Download certification file and put in asset of android project.
  2. Run the following code to make android trust this certification.
httpsURLConnection.setSSLSocketFactory(trustCert().getSocketFactory());

private SSLContext trustCert() throws CertificateException,IOException,KeyStoreException,
	NoSuchAlgorithmException,KeyManagementException {
	AssetManager assetManager = getAssets();
	CertificateFactory cf = CertificateFactory.getInstance("X.509");
	Certificate ca = cf.generateCertificate(assetManager.open("COMODORSADomainValidationSecureServerCA.crt"));

	// Create a KeyStore containing our trusted CAs
	String keyStoreType = KeyStore.getDefaultType();
	KeyStore keyStore = KeyStore.getInstance(keyStoreType);
	keyStore.load(null, null);
	keyStore.setCertificateEntry("ca", ca);

	// Create a TrustManager that trusts the CAs in our KeyStore
	String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
	TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
	tmf.init(keyStore);

	// Create an SSLContext that uses our TrustManager
	SSLContext context = SSLContext.getInstance("TLS");
	context.init(null, tmf.getTrustManagers(), null);
	return context;
}

But I think it's just a compromise solution for those who cannot wait.
The ultimate way is the server need to correct it to make certification work on android.

great it working well

@hasnabbas
Copy link
Author

The solution @HasnainAD mentioned worked.

  1. Download certification file and put in asset of android project.
  2. Run the following code to make android trust this certification.
httpsURLConnection.setSSLSocketFactory(trustCert().getSocketFactory());

private SSLContext trustCert() throws CertificateException,IOException,KeyStoreException,
	NoSuchAlgorithmException,KeyManagementException {
	AssetManager assetManager = getAssets();
	CertificateFactory cf = CertificateFactory.getInstance("X.509");
	Certificate ca = cf.generateCertificate(assetManager.open("COMODORSADomainValidationSecureServerCA.crt"));

	// Create a KeyStore containing our trusted CAs
	String keyStoreType = KeyStore.getDefaultType();
	KeyStore keyStore = KeyStore.getInstance(keyStoreType);
	keyStore.load(null, null);
	keyStore.setCertificateEntry("ca", ca);

	// Create a TrustManager that trusts the CAs in our KeyStore
	String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
	TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
	tmf.init(keyStore);

	// Create an SSLContext that uses our TrustManager
	SSLContext context = SSLContext.getInstance("TLS");
	context.init(null, tmf.getTrustManagers(), null);
	return context;
}

But I think it's just a compromise solution for those who cannot wait.
The ultimate way is the server need to correct it to make certification work on android.

Hey max, thanks for the code, do I need to run it one time per session or everytime before starting a call?

@remyasics
Copy link

httpsURLConnection.setSSLSocketFactory(trustCert().getSocketFactory());
where should I add this line of code.I am using AsyncHttpURLConnection in my code

@hasnabbas
Copy link
Author

@remyasics Use Https instead of Http

@maxvuluy
Copy link

maxvuluy commented Nov 8, 2018

@HasnainAD
trustCert() only called once, then you can use the produced SSLContext multiple times.

@remyasics

private void sendHttpMessage() {
    try {
      HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
      ...
      if (connection instanceof HttpsURLConnection) {
        ((HttpsURLConnection) connection).setSSLSocketFactory(sslContext.getSocketFactory());
      }
      ...
      // Get response.
      int responseCode = connection.getResponseCode();
      ...
    } catch (SocketTimeoutException e) {
      events.onHttpError("HTTP " + method + " to " + url + " timeout");
    } catch (IOException e) {
      events.onHttpError("HTTP " + method + " to " + url + " error: " + e.getMessage());
    }
  }

@hasnabbas
Copy link
Author

hasnabbas commented Nov 8, 2018

@maxvuluy how to use it with AsyncHttpURLConnection?

Following is my code:

 httpConnection =
                new AsyncHttpURLConnection("POST", roomUrl, roomMessage, new AsyncHttpEvents() {
                    @Override
                    public void onHttpError(String errorMessage) {
                        Log.e(TAG, "Room connection error: " + errorMessage);
                        events.onSignalingParametersError(errorMessage);
                    }

                    @Override
                    public void onHttpComplete(String response) {
                        roomHttpResponseParse(response);
                    }
                });
        httpConnection.send();

@remyasics
Copy link

@remyasics

private void sendHttpMessage() {
    try {
      HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
      ...
      if (connection instanceof HttpsURLConnection) {
        ((HttpsURLConnection) connection).setSSLSocketFactory(sslContext.getSocketFactory());
      }
      ...
      // Get response.
      int responseCode = connection.getResponseCode();
      ...
    } catch (SocketTimeoutException e) {
      events.onHttpError("HTTP " + method + " to " + url + " timeout");
    } catch (IOException e) {
      events.onHttpError("HTTP " + method + " to " + url + " error: " + e.getMessage());
    }
  }

Thank you

@remyasics
Copy link

AssetManager assetManager = getAssets();

is giving me error

@maxvuluy
Copy link

maxvuluy commented Nov 8, 2018

@HasnainAD I modified AsyncHttpURLConnection as below
@remyasics I'm sorry. getAssets() is a function of Context.
You can put turstCert() in a Activity.

public class AsyncHttpURLConnection {
    private static SSLContext sslContext;

    public static setSSLContext(SSLContext sslContext) {
        this.sslContext = sslContext;
    }

    private void sendHttpMessage() {
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            ...
            if (connection instanceof HttpsURLConnection) {
                ((HttpsURLConnection) connection).setSSLSocketFactory(sslContext.getSocketFactory());
            }
            ...
            // Get response.
            int responseCode = connection.getResponseCode();
            ...
        }
    }
}

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onResume() {
        super.onResume();
        try {
            AsyncHttpURLConnection.setSSLContext(trustCert());
        } catch (CertificateException | IOException | NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
            e.printStackTrace();
        }
    }

    private SSLContext trustCert() throws CertificateException,IOException,KeyStoreException,NoSuchAlgorithmException,KeyManagementException {
        AssetManager assetManager = getAssets();
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        Certificate ca = cf.generateCertificate(assetManager.open("COMODORSADomainValidationSecureServerCA.crt"));

        // Create a KeyStore containing our trusted CAs
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);

        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

        // Create an SSLContext that uses our TrustManager
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, tmf.getTrustManagers(), null);
        return context;
    }
}

@hasnabbas
Copy link
Author

👍 @maxvuluy Thanks a lot man! I got it working.

@remyasics
Copy link

@HasnainAD Thanks a lot

@remyasics
Copy link

I think since it has certificate verification we can use it for production also.Any idea?

@maxvuluy
Copy link

maxvuluy commented Nov 9, 2018

I thought this issue is not completely solved.
I use openssl to trace certificate chain of appr.tc

openssl s_client -connect appr.tc:443 -servername appr.tc
---
Certificate chain
 0 s:/OU=Domain Control Validated/OU=PositiveSSL/CN=appr.tc
   i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA
---

According to COMODO's explanation and android guide, the certificate chain of server seems to be incomplete.
Is there any member of WebRTC can help confirm this issue?

The solution with TrustManager is just a compromise. I don't think it's a good solution.
It would be great if manager of appr.tc could help solve this issue.
@HasnainAD could you help re-open this issue? Thanks.

@einsteinarbert
Copy link

einsteinarbert commented Nov 26, 2018

Does appr.tc website error cert? Because I don't think project error, because my code not update for along and when I come back, this error suddenly appear

@valon91
Copy link

valon91 commented Mar 7, 2019

httpsURLConnection.setSSLSocketFactory(trustCert().getSocketFactory());

where to write this code, how to call it? I am using volley for parsing JSON , please help

@vj12354
Copy link

vj12354 commented Apr 9, 2020

I had similar issue and mange to solve it by following steps described in https://developer.android.com/training/articles/security-config

But the config changes, without any complicated code logic, would only work on Android version 24 & above.

So for android lower then N (version 24) the solution is to via code changes as mentioned above. If you are using OkHttp, then follow the customTrust:
https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CustomTrust.java

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

No branches or pull requests

8 participants