java - Android 应用程序中的 2 向 SSL 不起作用

标签 java android ssl

我正在尝试创建一个使用双向 SSL 与 NodeJS 应用程序通信的 Android 应用程序。我有 2 个版本的代码来发出请求,但两个版本都不起作用。如果我使用纯 Java 运行代码的第一个版本,它就可以工作,但是当我尝试将其引入我的 Android 应用程序时,服务器无法识别客户端证书:

版本 1:

    System.setProperty("javax.net.ssl.keyStore", "jks-keystore.jks");
    System.setProperty("javax.net.ssl.keyStorePassword", "pass1");
    System.setProperty("javax.net.ssl.trustStore", "jkstruststore.jks");
    System.setProperty("javax.net.ssl.trustStorePassword", "pass2");



    // specify url
    String url = "https://example.com/startup";

    System.out.println("Startup URL is " + url);

    // This block of code keeps self-signed certificates from causing errors.
    javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
        new javax.net.ssl.HostnameVerifier(){
            public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
                return true;
            }
        }
    );

    // initiate the request
    try
    {
        URL hp = new URL(url);
        HttpsURLConnection hpCon = (HttpsURLConnection)hp.openConnection();

        boolean isProxy = hpCon.usingProxy();
        InputStream obj = (InputStream) hpCon.getInputStream();

        // print out JSON response
        System.out.println(convertStreamToString(obj));
    }
    catch (Exception ex)
    {
        ex.printStackTrace();
    }

错误一:

03-17 12:25:18.616: W/System.err(331): javax.net.ssl.SSLHandshakeException:     
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

版本 2:

          // load truststore certificate
          InputStream clientTruststoreIs = getResources().openRawResource(R.raw.tsserver);
          KeyStore trustStore = null;
          trustStore = KeyStore.getInstance("BKS");
          trustStore.load(clientTruststoreIs, "pass1".toCharArray());

          System.out.println("Loaded server certificates: " + trustStore.size());

          // initialize trust manager factory with the read truststore
          TrustManagerFactory trustManagerFactory = null;
          trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
          trustManagerFactory.init(trustStore);

          // setup client certificate

          // load client certificate
          InputStream keyStoreStream = getResources().openRawResource(R.raw.tsclient);
          KeyStore keyStore = null;
          keyStore = KeyStore.getInstance("BKS");
          keyStore.load(keyStoreStream, "pass2".toCharArray());

          System.out.println("Loaded client certificates: " + keyStore.size());

          // initialize key manager factory with the read client certificate
          KeyManagerFactory keyManagerFactory = null;
          keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
          keyManagerFactory.init(keyStore, "pass2".toCharArray());


          // initialize SSLSocketFactory to use the certificates
          SSLSocketFactory socketFactory = new SSLSocketFactory(SSLSocketFactory.TLS, keyStore, "pass2", trustStore, null, null);

          // Set basic data
          HttpParams params = new BasicHttpParams();
          HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
          HttpProtocolParams.setContentCharset(params, "UTF-8");
          HttpProtocolParams.setUseExpectContinue(params, true);
          HttpProtocolParams.setUserAgent(params, "Android app/1.0.0");

          // Make pool
          ConnPerRoute connPerRoute = new ConnPerRouteBean(12);
          ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);
          ConnManagerParams.setMaxTotalConnections(params, 20);

          // Set timeout
          HttpConnectionParams.setStaleCheckingEnabled(params, false);
          HttpConnectionParams.setConnectionTimeout(params, 20 * 1000);
          HttpConnectionParams.setSoTimeout(params, 20 * 1000);
          HttpConnectionParams.setSocketBufferSize(params, 8192);

          // Some client params
          HttpClientParams.setRedirecting(params, false);

          // Register http/s schemas!
          SchemeRegistry schReg = new SchemeRegistry();
          schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
          schReg.register(new Scheme("https", socketFactory, 443));
          ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);
          DefaultHttpClient sClient = new DefaultHttpClient(conMgr, params);

          try {
                String res = executeHttpGet(sClient, "https://example.com/startup");
                System.out.println("------- SSL RESULT IS = " + res);
            } catch (Exception e) {
                System.out.println("---- ex " + e.getMessage());
                e.printStackTrace();
            }

错误2:服务器没有看到客户端证书

这两个代码示例都会导致服务器看不到客户端证书。任何想法为什么这不起作用?谢谢。

最佳答案

如果我们仔细阅读documentaion我们可以发现:

自签名证书会抛出与您遇到的类似的错误。对于服务器而言,自签名证书被信任以无任何错误地通过并不重要,在任何一种情况下都会抛出 SSLHandshakeException。

为了通过这是组装一组受信任的 CA 证书并将它们添加到您的信任库中。然后从该 CA 发出的所有证书都将受到信任,这将忽略将它们直接添加到 da truststore 文件中的需要。

现在如何将 CA 可信证书添加到信任库:

设置您自己的 CA here

然后:

给定 CA 证书cacert.pem,PEM 格式,您可以将证书添加到 JKS 通过输入以下命令来创建信任库(或创建新的信任库):

keytool -import -file cacert.pem -alias CAAlias -keystore truststore.ts -storepass StorePass 

其中 CAAlias 是一个方便的标签,使您能够使用 keytool 实用程序访问此特定的 CA 证书。文件 truststore.ts 是一个包含 CA 证书 的 keystore 文件——如果此文件尚不存在,keytool 实用程序会创建一个。 StorePass 密码提供对 keystore 文件 truststore.t

的访问

看这个document .

关于java - Android 应用程序中的 2 向 SSL 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29124250/

相关文章:

java - 在 JDO 查询中忽略大小写

java - 循环访问条目集合时的性能

android - 在 Android 中获取 UARFCN 和 SC

c - openSSL key block 访问功能?

ssl - 获取 SSL 证书信息 - UIWebview

SSL:服务器 key 长度和浏览器连接信息。基础理解

java-cassnadra object Frozen annotation for address map<text, frozen<list<frozen<address>>>>,

java - Android设备java中的串行通信

android - 在 android 平台上使用 http 有效地发送 Protocol Buffer 消息

java - 加载屏幕后显示操作栏