Smack: “Trust anchor for certification path not fo

2019-04-17 10:04发布

I'm trying to connect from Android to a Apache Vysper XMPP server in localhost. I'm using Smack framework to perform XMPP operations:

AbstractXMPPConnection connection = new XMPPTCPConnection("bigdestroyer", "", ip);
  try {
      connection.setPacketReplyTimeout(10000);        
      connection.connect();
  } catch (SmackException e) {
      e.printStackTrace();
  } catch (IOException e) {
      e.printStackTrace();
  } catch (XMPPException e) {
      e.printStackTrace();
  }

But I get this error:

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

I guess it is related to SSL certificate but I don't know what I have to do. Can you help me?

I have tried to put cert file (the same as the server has) in assets folder and create the connection this way:

  XMPPTCPConnectionConfiguration connectionConfiguration = configuration.setConnectTimeout(10000)
                    .setUsernameAndPassword("admin", "admin")
                    .setHost(ip)
                    .setServiceName(ip)
                    .setKeystorePath("file:///android_asset/bogus_mina_tls.cert")
                    .build();

XMPPTCPConnection connection = new XMPPTCPConnection(connectionConfiguration);

But it still doesn't work. Any suggestion?

3条回答
叛逆
2楼-- · 2019-04-17 10:36

The KeystorePath should point to a Keystore, not a simple certificate. Android uses KeystoreType BKS by default, so you should create one and import your certificate into it as described by http://blog.antoine.li/2010/10/22/android-trusting-ssl-certificates/

keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/myKeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret

You can also do this using Portecle (http://portecle.sourceforge.net/), if you don't want to mess with the command line.

查看更多
Rolldiameter
3楼-- · 2019-04-17 10:41

Android Training might solve this exact problem:

Common Problems Verifying Server Certificates This can happen for several reasons, including:

  1. The 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

The following sections discuss how to address these problems while keeping your connection to the server secure.

Unknown certificate authority

In this case, the SSLHandshakeException occurs because you have a CA that isn't trusted by the system. It could be because you have a certificate from a new CA that isn't yet trusted by Android or your app is running on an older version without the CA. More often a CA is unknown because it isn't a public CA, but a private one issued by an organization such as a government, corporation, or education institution for their own use.

Fortunately, you can teach HttpsURLConnection to trust a specific set of CAs. The procedure can be a little convoluted, so below is an example that takes a specific CA from an InputStream, uses it to create a KeyStore, which is then used to create and initialize a TrustManager. A TrustManager is what the system uses to validate certificates from the server and—by creating one from a KeyStore with one or more CAs—those will be the only CAs trusted by that TrustManager.

Given the new TrustManager, the example initializes a new SSLContext which provides an SSLSocketFactory you can use to override the default SSLSocketFactory from HttpsURLConnection. This way the connection will use your CAs for certificate validation.

Here is the example in full using an organizational CA from the University of Washington:

    // 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 URLConnection to use a SocketFactory from our SSLContext
    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);

With a custom TrustManager that knows about your CAs, the system is able to validate that your server certificate come from a trusted issuer.

Caution: Many web sites describe a poor alternative solution which is to install a TrustManager that does nothing. If you do this you might as well not be encrypting your communication, because anyone can attack your users at a public Wi-Fi hotspot by using DNS tricks to send your users' traffic through a proxy of their own that pretends to be your server. The attacker can then record passwords and other personal data. This works because the attacker can generate a certificate and—without a TrustManager that actually validates that the certificate comes from a trusted source—your app could be talking to anyone. So don't do this, not even temporarily. You can always make your app trust the issuer of the server's certificate, so just do it.

The page continues with additional possibilities, but this one seems like it may be the most relevant.

查看更多
The star\"
4楼-- · 2019-04-17 10:59

There are 2 approaches to solve your problem:

  1. Fix your server by having it's certificates signed by a trusted 3rd party.

  2. Have your client accept the self-signed certificate you are using right now.

查看更多
登录 后发表回答