OkHttp javax.net.ssl.SSLPeerUnverifiedException:主机名 domain.com 未验证

新手上路,请多包涵

几天来我一直在努力让这个工作。我正在尝试使用自签名证书通过 https 连接到我的服务器。我认为现在没有任何页面或示例是我未读过的。

我做了什么:

  1. 按照本教程创建了 bks 密钥库:http: //blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html

它使用 openssl s_client -connect domain.com:443 从服务器获取证书。然后使用充气城堡创建一个 bks 密钥库。

  1. 从原始文件夹中读取创建的密钥库,将其添加到 sslfactory,然后添加到 OkHttpClient。像这样:
    public ApiService() {
       mClient = new OkHttpClient();
       mClient.setConnectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS);
       mClient.setReadTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS);
       mClient.setCache(getCache());
       mClient.setCertificatePinner(getPinnedCerts());
       mClient.setSslSocketFactory(getSSL());
   }

   protected SSLSocketFactory getSSL() {
       try {
           KeyStore trusted = KeyStore.getInstance("BKS");
           InputStream in = Beadict.getAppContext().getResources().openRawResource(R.raw.mytruststore);
           trusted.load(in, "pwd".toCharArray());
           SSLContext sslContext = SSLContext.getInstance("TLS");
           TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
           trustManagerFactory.init(trusted);
           sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
           return sslContext.getSocketFactory();
       } catch(Exception e) {
           e.printStackTrace();
       }
       return null;
   }

   public CertificatePinner getPinnedCerts() {
       return new CertificatePinner.Builder()
               .add("domain.com", "sha1/theSha=")
               .build();
   }

  1. 由于某种原因,这总是会生成一个 SSLPeerUnverifiedException 有或没有密钥库。有或没有 CertificatePinner
    javax.net.ssl.SSLPeerUnverifiedException: Hostname domain.com not verified: 0
    W/System.err﹕ certificate: sha1/theSha=
    W/System.err﹕ DN: 1.2.840.113549.1.9.1=#1610696e666f40626561646963742e636f6d,CN=http://domain.com,OU=development,O=domain,L=Valencia,ST=Valencia,C=ES
    W/System.err﹕ subjectAltNames: []
    W/System.err﹕ at com.squareup.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:124)
    W/System.err﹕ at com.squareup.okhttp.Connection.connect(Connection.java:143)
    W/System.err﹕ at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:185)
    W/System.err﹕ at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)
    W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341)
    W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:330)
    W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)
    W/System.err﹕ at com.squareup.okhttp.Call.getResponse(Call.java:273)
    W/System.err﹕ at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:230)
    W/System.err﹕ at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:201)
    W/System.err﹕ at com.squareup.okhttp.Call.execute(Call.java:81)
    ...

我究竟做错了什么?

原文由 just_user 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 858
2 个回答

我终于得到了这个混合多个答案的工作。

首先,证书制作错误,不确定如何制作。但是通过使用 此答案 中的脚本创建它们使它们起作用。需要的是服务器证书和密钥。然后客户需要另一个证书。

要在 android 中使用证书,我将 .pem 文件转换为 .crt 文件,如下所示:

 openssl x509 -outform der -in client.pem  -out client.crt

在 android 中,我将证书添加到我的 OkHttp 客户端,如下所示:

 public ApiService() {
    mClient = new OkHttpClient();
    mClient.setConnectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS);
    mClient.setReadTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS);
    mClient.setCache(getCache());
    mClient.setSslSocketFactory(getSSL());
}

protected SSLSocketFactory getSSL() {
    try {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream cert = getAppContext().getResources().openRawResource(R.raw.client);
        Certificate ca = cf.generateCertificate(cert);
        cert.close();

        // creating a KeyStore containing our trusted CAs
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);

        return new AdditionalKeyStore(keyStore);
    } catch(Exception e) {
        e.printStackTrace();
    }
    return null;
}

new AdditionalKeyStore() 的最后一部分取自 这个写得很好的答案。它添加了一个后备密钥库。

我希望这可以帮助其他人!这是让 HTTPS 使用我找到的自签名证书的最简单方法。其他方法包括拥有一个 BouncyCastle 密钥库,这对我来说似乎太过分了。

原文由 just_user 发布,翻译遵循 CC BY-SA 3.0 许可协议

我遇到了同样的问题,但是我需要我的应用程序在多个暂存环境中工作,所有这些环境都有自签名证书。更糟糕的是,他们可以即时更改这些证书。

为了解决这个问题,当仅连接到暂存时,我添加了一个信任所有证书的 SSLSocketFactory。这修复了 java 错误,但是它给我留下了这张票中提到的 okhttp 异常。

为避免此错误,我需要向我的 okHttpClient 添加更多自定义项。这为我修复了错误。

 okHttpClient.setHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });

原文由 Jake Hall 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题