2

我遇到的问题是我得到了一个 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
4

1 回答 1

0

首先将您的keystoreand复制trustoreassets文件夹,然后尝试使用此代码(Get 方法):

KeyStore keyStore_manager = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore_manager.load(_context.getAssets().open(your_keystore),password.toCharArray());
KeyStore keyStore_trust = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore_trust.load(_context.getAssets().open(your_trustore),password.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore_manager, password.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore_trust);
HttpsURLConnection.setDefaultHostnameVerifier(new NullHostNameVerifier());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(),tmf.getTrustManagers(), null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
URL url = new URL(your_url);
HttpsURLConnection urlConnection = (HttpsURLConnection) requestedUrl.openConnection();
if (urlConnection instanceof HttpsURLConnection)
{
    ((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslContext
            .getSocketFactory());
}
urlConnection.setRequestMethod("GET");
urlConnection.setConnectTimeout(1500);
urlConnection.connect();
String data = "";
int http_status = urlConnection.getResponseCode();
if (http_status == 200)
{
//read data sent from server
    InputStream response = new BufferedInputStream(

    urlConnection.getInputStream());

    int bytesRead = -1;
    byte[] buffer = new byte[30 * 1024];
    while ((bytesRead = response.read(buffer)) > 0)
    {
        data = new String(buffer, 0, bytesRead);
    }

}
urlConnection.disconnect();
于 2014-04-09T10:07:18.197 回答