Java security cert certpathvalidatorexception как исправить

I am answering to this to give an idea about the scenario and solution as per the android developer site for others benefit. I have solved this using custom trust manager.

The problem was with the server certificate, it misses intermediate certificate authority. However with the first flow certificate path is completed somehow and result was successful certificate path validation.

There is a solution for this in android developer site. it suggest to use custom trust manager that trusts this server certificate or it suggest to server to include the intermediate CA in the server chain.

custom trust manager. source: https://developer.android.com/training/articles/security-ssl.html#UnknownCa

// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
Certificate ca;
try {
    ca = cf.generateCertificate(caInput);
    System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
    caInput.close();
}

// 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);
// Tell the okhttp to use a SocketFactory from our SSLContext
OkHttpClient okHttpClient client = new OkHttpClient.Builder().sslSocketFactory(context.getSocketFactory()).build();

UPDATE: My problem was solved after intermediate certificate authority added to the certificate chain from the server side. It is the best solution, Bundling the certificate with the app requires app to be updated on certificate expiring or any other issues related with certificate management.

UPDATE:03/09/2017 Easiest way to load certificate file I found is use of raw resource.

InputStream caInput = new BufferedInputStream(context
                .getResources().openRawResource(R.raw.certfilename));

where certfilename is the certificate file placed in resources/raw folder. Also okhttp’s sslSocketFactory(SSLSocketFactory sslSocketFactory) has been deprecated and suggested approach in the okhttp api doc can be used.

Also when getting the certificate from the server it is better to use openssl.

openssl s_client -connect {server-address}:{port} -showcerts

Because I used to grab that from firefox and faced situation where it was altered by the virus guard.

Below error message throwing when sent the API request. We have already configured the valid SSL Certificate of this domain, even no error message showing when open the browser.

SSL Cert provider: komodo

Caused by: java.security.cert.CertPathValidatorException: CA key usage
check failed: keyCertSign bit is not set
at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:139)
at sun.security.provider.certpath.PKIXCertPathValidator.doValidate(PKIXCertPathValidator.java:326)
at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:178)
at java.security.cert.CertPathValidator.validate(CertPathValidator.java:250)
at sun.security.validator.PKIXValidator.doValidate(PKIXValidator.java:246)

How can i resolve this problem ?

asked Dec 5, 2013 at 6:10

sprabhakaran's user avatar

sprabhakaransprabhakaran

1,6055 gold badges20 silver badges36 bronze badges

Comments

@valery-lavrik

@valery-lavrik
valery-lavrik

changed the title
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found

react-native: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found

Nov 15, 2022

@valery-lavrik
valery-lavrik

changed the title
react-native: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found

java.security.cert.CertPathValidatorException: Trust anchor for certification path not found (app in react-native)

Nov 15, 2022

Recently I was working on a chat application for the android platform, everything regarding the remote/networking implementation worked flawlessly. I used the Retrofit networking library and socket.io. At the time, the base url was without SSL (that is the HTTP scheme — http://api.example.com)

Just before we rolled out the MVP for beta testing, we acquired a domain name and enabled SSL on the server. This meant the base URL scheme became HTTPS (e.g https://api.example.com).

The change on the app to use a secured URL broke the entire app. All the endpoints were not connecting to the server successfully. Basically the network handshake process between the client and server wasn’t successful. Below is what the the error on the log was like

<-- HTTP FAILED: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

Enter fullscreen mode

Exit fullscreen mode

After doing a little research I discovered it was an issue with the server certificate not being trusted by the android system. This could be because of any of the reasons below:

  1. The Certificate Authority (CA) that issued the server certificate was unknown.

  2. The server certificate wasn’t signed by a CA, but was self signed.

  3. The server configuration is missing an intermediate CA.

In my case, this issue existed because the server certificate was self signed.

From android documentation there is a clean way to configure the app to trust your own self-signed certificates, which I will outline in 3 steps.

Step 1

Add the crt file to the raw folder.

This file will be retrieved from the server. You can request for the digital certificate from the backend engineer. It should come in a .crt extension.

crt file

Step 2

Create an XML network security config file (network_security_config.xml) like below:

XML network security config file

network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">api.example.com</domain>
        <trust-anchors>
            <certificates src="@raw/certificate" />
        </trust-anchors>
    </domain-config>
</network-security-config>

Enter fullscreen mode

Exit fullscreen mode

Step 3

Specify the network configuration settings in the Manifest.xml file of your application.

android manifest file

With these 3 steps done, you should connect seamlessly with the backend without any further issues.

plan 1

try {
  CertificateFactory cf = CertificateFactory.getInstance("X.509");
     // uwca.crt packaged in the asset, the certificate can be downloaded from https://itconnect.uw.edu/security/securing-computer/install/safari-os-x/
  InputStream caInput = new BufferedInputStream(getAssets().open("uwca.crt"));
  Certificate ca;
  try {
      ca = cf.generateCertificate(caInput);
      Log.i("Longer", "ca=" + ((X509Certificate) ca).getSubjectDN());
      Log.i("Longer", "key=" + ((X509Certificate) ca).getPublicKey();
  } finally {
      caInput.close();
  }

  // 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("TLSv1","AndroidOpenSSL");
  context.init(null, tmf.getTrustManagers(), null);

  URL url = new URL("https://certs.cac.washington.edu/CAtest/");
  HttpsURLConnection urlConnection =
          (HttpsURLConnection)url.openConnection();
  urlConnection.setSSLSocketFactory(context.getSocketFactory());
  InputStream in = urlConnection.getInputStream();
  copyInputStreamToOutputStream(in, System.out);
} catch (CertificateException e) {
  e.printStackTrace();
} catch (IOException e) {
  e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
  e.printStackTrace();
} catch (KeyStoreException e) {
  e.printStackTrace();
} catch (KeyManagementException e) {
  e.printStackTrace();
} catch (NoSuchProviderException e) {
  e.printStackTrace();
}

Scenario 2

With Scheme 1, a package to the inside of the App certificate, but not through a TrustManager KeyStore to guide generated, but simply implement a custom a TrustManager, to realize his checking logic; checking logic including:

• The server certificate is expired
• Certificate Signing legality

try {
  CertificateFactory cf = CertificateFactory.getInstance("X.509");
     // uwca.crt packaged in the asset, the certificate can be downloaded from https://itconnect.uw.edu/security/securing-computer/install/safari-os-x/
  InputStream caInput = new BufferedInputStream(getAssets().open("uwca.crt"));
  final Certificate ca;
  try {
      ca = cf.generateCertificate(caInput);
      Log.i("Longer", "ca=" + ((X509Certificate) ca).getSubjectDN());
      Log.i("Longer", "key=" + ((X509Certificate) ca).getPublicKey());
  } finally {
      caInput.close();
  }
  // Create an SSLContext that uses our TrustManager
  SSLContext context = SSLContext.getInstance("TLSv1","AndroidOpenSSL");
  context.init(null, new TrustManager[]{
          new X509TrustManager() {
              @Override
              public void checkClientTrusted(X509Certificate[] chain,
                      String authType)
                      throws CertificateException {

              }

              @Override
              public void checkServerTrusted(X509Certificate[] chain,
                      String authType)
                      throws CertificateException {
                  for (X509Certificate cert : chain) {

                      // Make sure that it hasn't expired.
                      cert.checkValidity();

                      // Verify the certificate's public key chain.
                      try {
                          cert.verify(((X509Certificate) ca).getPublicKey());
                      } catch (NoSuchAlgorithmException e) {
                          e.printStackTrace();
                      } catch (InvalidKeyException e) {
                          e.printStackTrace();
                      } catch (NoSuchProviderException e) {
                          e.printStackTrace();
                      } catch (SignatureException e) {
                          e.printStackTrace();
                      }
                  }
              }

              @Override
              public X509Certificate[] getAcceptedIssuers() {
                  return new X509Certificate[0];
              }
          }
  }, null);

  URL url = new URL("https://certs.cac.washington.edu/CAtest/");
  HttpsURLConnection urlConnection =
          (HttpsURLConnection)url.openConnection();
  urlConnection.setSSLSocketFactory(context.getSocketFactory());
  InputStream in = urlConnection.getInputStream();
  copyInputStreamToOutputStream(in, System.out);
} catch (CertificateException e) {
  e.printStackTrace();
} catch (IOException e) {
  e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
  e.printStackTrace();
} catch (KeyManagementException e) {
  e.printStackTrace();
} catch (NoSuchProviderException e) {
  e.printStackTrace();
}

Scenario 3 (recommended)


    // Certificate Trust
    public final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };
 // Certificate Trust
 // critical code
if (url.getProtocol().toUpperCase().equals("HTTPS")) {
        trustAllHosts();
        HttpsURLConnection https = (HttpsURLConnection) url
                .openConnection();
        https.setHostnameVerifier(DO_NOT_VERIFY);
        conn = https;
    } else {
        conn = (HttpURLConnection) url.openConnection();
    }
 // critical code

    public static void trustAllHosts() {
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[]{};
            }

            public void checkClientTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }
        }};
        // Install the all-trusting trust manager
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection
                    .setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Понравилась статья? Поделить с друзьями:

Не пропустите также:

  • Как найти английские буквы на клавиатуре телефона
  • Как найти фонд риска
  • Даны векторы найдите координаты вектора как решать
  • Как найти телефон жкх по адресу
  • Как это исправить чем лечить

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии