我遇到的问题是我得到了一个 SSLHandshakeException,它只出现在任何 Android 2.3 手机上,但不会出现在较新的(Android 4+)手机上。
为了接受服务器的证书,我从我的资源中读取了保存的证书,并将其与用于此连接的 TrustManager 连接。
Google 推荐了这种做法(2014 年 4 月 9 日):http: //developer.android.com/training/articles/security-ssl.html
异常堆栈跟踪输出:
04-09 07:25:15.739: W/ShopLoader(2079):
javax.net.ssl.SSLHandshakeException:
java.security.cert.CertPathValidatorException:
Trust anchor for certification path not found.:
java.security.cert.CertPathValidatorException:
Trust anchor for certification path not found.
我的代码:
private static InputStream getSecureStream(String urlString) throws KeyStoreException, KeyManagementException, NoSuchAlgorithmException, IOException, CertificateException {
Context appCtx = MyBackgroundService.instance.context;
Resources res = appCtx.getResources();
InputStream is = res.openRawResource(res.getIdentifier("de_ssl_2014", "raw", appCtx.getPackageName()));
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(is);
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(urlString);
HttpsURLConnection urlConnection =
(HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
return in;
}
异常前的输出:
04-09 07:58:46.869: I/System.out(3282): ca=CN=api.xxxxxxxx.de, OU=Domain Control Validated - RapidSSL(R), OU=See www.rapidssl.com/resources/cps (c)13, OU=GT40709841, OID.2.5.4.5=0JfY9NNUOGmytnt1WE//sOqJj7JzTtCg
OpenSSL 连接返回:
openssl s_client -connect api.xxxxxxxx.de:443
CONNECTED(00000003)
depth=1 /C=US/O=GeoTrust, Inc./CN=RapidSSL CA
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
0 s:/serialNumber=0JfY9NNUOGmytnt1WE//sOqJj7JzTtCg/OU=GT40709841/OU=See www.rapidssl.com/resources/cps (c)13/OU=Domain Control Validated - RapidSSL(R)/CN=api.xxxxxxxx.de
i:/C=US/O=GeoTrust, Inc./CN=RapidSSL CA
1 s:/C=US/O=GeoTrust, Inc./CN=RapidSSL CA
i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIFJjCCBA6gAwIBAgIDD2BUMA0GCSqGSIb3DQEBCwUAMDwxCzAJBgNVBAYTAlVT
[...]
jIhiyCMrPZ9VU6QqWQ7tslmtR54SpINwCzFVE6ySWC9CY8m8+PtWyfDDPwWzuJLO
UlxESqqQXD7iZJequBUoiLYCQTc7kofp/LU=
-----END CERTIFICATE-----
subject=/serialNumber=0JfY9NNUOGmytnt1WE//sOqJj7JzTtCg/OU=GT40709841/OU=See www.rapidssl.com/resources/cps (c)13/OU=Domain Control Validated - RapidSSL(R)/CN=api.xxxxxxxx.de
issuer=/C=US/O=GeoTrust, Inc./CN=RapidSSL CA
---
No client certificate CA names sent
---
SSL handshake has read 3129 bytes and written 316 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 2048 bit
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : DHE-RSA-AES256-SHA
Session-ID: C037859AE2DDF571DCC6D7C0C6C7D22CE34E7A3DC1BE6BB5E286B66A3EAA5492
Session-ID-ctx:
Master-Key: FE598D2380B14A0C73B6FBFBFB51C977579AE12CB37077769922D0E90C4AF5487B43EBC02433F1CAA6134CF60F4EBB34
Key-Arg : None
Start Time: 1397029699
Timeout : 300 (sec)
Verify return code: 20 (unable to get local issuer certificate)
---
closed