Smack:"未找到认证路径的信任锚"

时间:2015-09-03 11:08:39

标签: java android ssl xmpp 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证书有关,但我不知道自己该做什么。你能救我吗?

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

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

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

3 个答案:

答案 0 :(得分:2)

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/)执行此操作。

答案 1 :(得分:1)

Android Training可能会解决这个问题:

  

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

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

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

         

    未知的证书颁发机构

         

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

         

    幸运的是,您可以教HttpsURLConnection来信任特定的集合   CA.这个程序可能有点复杂,所以下面是一个   从InputStream获取特定CA的示例,使用它   创建一个KeyStore,然后用于创建和初始化   的TrustManager。 TrustManager是系统用于验证的内容   来自服务器的证书,并通过从KeyStore创建一个   一个或多个CA--这些CA将是唯一受其信任的CA.   的TrustManager。

         

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

         

    以下是完整使用组织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,系统是   能够验证您的服务器证书来自可信任的   发行者。

     

警告:很多网站都描述了一个糟糕的替代解决方案   安装一个什么都不做的TrustManager。如果你这样做,你可能会   以及不加密你的沟通,因为任何人都可以   使用DNS技巧攻击公共Wi-Fi热点上的用户   发送您的用户'通过他们自己的代理交换流量   是你的服务器。然后攻击者可以记录密码等   个人资料。这是有效的,因为攻击者可以生成一个   证书和 - 没有实际验证它的TrustManager   证书来自可靠的来源 - 您的应用可能正在谈论   对任何人。所以不要这样做,甚至不是暂时的。你总能做到   您的应用程序信任服务器证书的颁发者,所以就这样做。

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

答案 2 :(得分:0)

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

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

  2. 让您的客户accept the self-signed certificate you are using right now