java.security.cert.CertPathValidatorException:找不到证书路径的信任锚点。安卓 2.3

2022-09-04 20:54:49

在我的服务器(生产服务器)中,我有一个 goDaddy ssl 证书。我有iOS和Android应用程序与服务器连接,iOS连接没有问题,Android与版本4.*一切都很好,但是对于带有2.3.*的设备,我总是得到一个SSLHandshakeException。

我在Android开发人员页面上确实像(https://developer.android.com/training/articles/security-ssl.html)。

我已经在Stack Overflow(这里)中看到了类似的线程,但没有一个有帮助。

然后我看到这个线程在谈论扩展密钥用法,但在调试时,我得到了以下信息:

[2]: OID: 2.5.29.37, Critical: false
Extended Key Usage: [ "1.3.6.1.5.5.7.3.1", "1.3.6.1.5.5.7.3.2" ]

所以我猜证书不是“强制”扩展密钥用法。

此外,在此线程上还有其他一些可能的原因,例如日期/时间完全错误,这些都不存在。

考虑到这一点,我现在不知道问题可能出在哪里。

有什么建议吗?

编辑:堆栈跟踪如下:

08-04 16:54:30.139: W/System.err(4832): Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
08-04 16:54:30.149: W/System.err(4832):     at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:161)
08-04 16:54:30.149: W/System.err(4832):     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:664)
08-04 16:54:30.149: W/System.err(4832):     at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
08-04 16:54:30.159: W/System.err(4832):     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:474)

答案 1

我浏览了SO和网络上的很多地方来解决这个问题。这是为我工作的代码(Android 21):

ByteArrayInputStream derInputStream = new ByteArrayInputStream(app.certificateString.getBytes());
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509","BC");
X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(derInputStream);
String alias = "alias";//cert.getSubjectX500Principal().getName();

KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);
trustStore.setCertificateEntry(alias, cert);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(trustStore, null);
KeyManager[] keyManagers = kmf.getKeyManagers();

TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
URL url = new URL(someURL);
conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(sslContext.getSocketFactory());

app.certificateString是包含证书的字符串,例如:

static public String certificateString=
    "-----BEGIN CERTIFICATE-----\n" +
    "MIIGQTCCBSmgAwIBAgIHBcg1dAivUzANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UE" +
    "BhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBE" +
    ... a bunch of characters...
    "5126sfeEJMRV4Fl2E5W1gDHoOd6V==\n" +
    "-----END CERTIFICATE-----";

我已经测试过,如果它是自签名的,你可以在证书字符串中放入任何字符,只要你保持上面的确切结构。我使用笔记本电脑的终端命令行获取了证书字符串。我需要知道更多细节,让我知道。


答案 2

证书的颁发者似乎不在 2.3 设备的信任存储中。

查看 GoDaddy 证书的根证书和中间 ca,并检查 2.3 设备上是否存在这些证书。

有关获取 2.3 证书列表的信息,请参阅 http://www.andreabaccega.com/blog/2010/09/23/android-root-certification-authorities-list/

当只有根 CA 可用时,请确保您的 Web 服务器也根据请求提供中间证书。