Smack:“找不到认证路径的信任锚”

我正在尝试从Android连接到localhost中的Apache Vysper XMPP服务器。 我正在使用Smack框架来执行XMPP操作:

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(); } 

但我得到这个错误:

javax.net.ssl.SSLHandshakeException:java.security.cert.CertPathValidatorException:未找到证书路径的信任锚。

我想这与SSL证书有关,但我不知道我该做什么。 你能帮助我吗?

我试图在assets文件夹中放置cert文件(与服务器相同)并以这种方式创建连接:

  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); 

但它仍然无效。 有什么建议吗?

KeystorePath应指向密钥库,而不是简单证书。 Android默认使用KeystoreType BKS,因此您应该创建一个并将证书导入其中,如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 

如果您不想使用命令行,也可以使用Portecle( http://portecle.sourceforge.net/ )执行此操作。

Android培训可能会解决这个问题:

validation服务器证书的常见问题这可能由于多种原因而发生,包括:

  1. 颁发服务器证书的CA未知
  2. 服务器证书未由CA签名,但是已自签名
  3. 服务器配置缺少中间CA.

以下部分讨论如何在保持与服务器的连接安全的同时解决这些问题。

未知的证书颁发机构

在这种情况下,发生SSLHandshakeException是因为您有一个不受系统信任的CA. 这可能是因为您拥有来自尚未受Android信任的新CA的证书,或者您的应用程序在没有CA的旧版本上运行。 更常见的是CA是未知的,因为它不是公共CA,而是由诸如政府,公司或教育机构之类的组织为其自己使用而发布的私有CA.

幸运的是,您可以教HttpsURLConnection来信任一组特定的CA. 该过程可能有点复杂,因此下面是一个从InputStream获取特定CA的示例,使用它创建KeyStore,然后用于创建和初始化TrustManager。 TrustManager是系统用于validation来自服务器的证书的方法,并且通过从具有一个或多个CA的KeyStore创建一个证书 – 这些CA将是该TrustManager信任的唯一CA.

给定新的TrustManager,该示例初始化一个新的SSLContext,它提供了一个SSLSocketFactory,可用于覆盖HttpsURLConnection中的默认SSLSocketFactory。 这样,连接将使用您的CA进行证书validation。

以下是使用华盛顿大学的组织CA的完整示例:

  // 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); 

使用了解CA的自定义TrustManager,系统可以validation您的服务器证书是否来自受信任的颁发者。

警告:许多网站描述了一个糟糕的替代解决方案,即安装一个什么都不做的TrustManager。 如果您这样做,您可能也不会加密您的通信,因为任何人都可以通过使用DNS技巧通过他们自己的代理发送用户的流量来冒充您的服务器,从而在公共Wi-Fi热点攻击您的用户。 然后,攻击者可以记录密码和其他个人数据。 这是有效的,因为攻击者可以生成证书,而且没有实际validation证书来自可靠来源的TrustManager,您的应用可能正在与任何人交谈。 所以不要这样做,甚至不是暂时的。 您始终可以让您的应用程序信任服务器证书的颁发者,所以就这样做。

该页面继续提供其他可能性,但这个似乎可能是最相关的。

有两种方法可以解决您的问题:

  1. 通过让受信任的第三方签署证书来修复您的服务器。

  2. 让您的客户立即接受您正在使用的自签名证书 。