Android SSL HTTP-запрос с использованием самозаверяющего сертификата и CA

У меня есть приложение для android, которое подключается к веб-службе SSL, которую мы размещаем. Веб-сервер apache и имеет свой собственный CA, который мы создали, и самозаверяющий сертификат SSL.

я импортировал наш сертификат CA на планшет Android в разделе доверенные сертификаты пользователя в безопасности.

Я проверил доступ к веб-серверу и могу подтвердить, что сертификат веб-службы отображается как действительный (скриншот ниже)

Valid certificate

вот сертификат в настройках безопасности:

Trusted certificate

теперь, когда я пытаюсь получить доступ к веб-сервису в своем приложении, я получаю исключение "без однорангового сертификата".

это упрощенная реализация SSL:

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // allows network on main thread (temp hack)
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); 
    StrictMode.setThreadPolicy(policy);

    SchemeRegistry schemeRegistry = new SchemeRegistry();
    //schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
    schemeRegistry.register(new Scheme("https", newSSLSocketFactory(), 443));


    HttpParams params = new BasicHttpParams();

    SingleClientConnManager mgr = new SingleClientConnManager(params, schemeRegistry);

    HttpClient client = new DefaultHttpClient(mgr, params);

    HttpPost httpRequest = new HttpPost("https://our-web-service.com");

    try {
        client.execute(httpRequest);
    } catch (Exception e) {
        e.printStackTrace(); //
    }
}

/* 
 * Standard SSL CA Store Setup //
 */
private SSLSocketFactory newSSLSocketFactory() {

    KeyStore trusted;

    try {
        trusted = KeyStore.getInstance("AndroidCAStore");
        trusted.load(null, null);
        Enumeration<String> aliases = trusted.aliases();

        while (aliases.hasMoreElements()) {
            String alias = aliases.nextElement();
            X509Certificate cert = (X509Certificate) trusted.getCertificate(alias);
            Log.d("", "Alias="+alias);
            Log.d("", "Subject DN: " + cert.getSubjectDN().getName());
            Log.d("", "Issuer DN: " + cert.getIssuerDN().getName());
        }      

        SSLSocketFactory sf = new SSLSocketFactory(trusted);
        sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);

        return sf;

    } catch (Exception e) {
        // TODO Auto-generated catch block
        throw new AssertionError(e);
    }  
}

}

цикл while просто выплевывает сертификаты, и я вижу свой собственный CA в журналах. Но я все равно получаю " нет сертификата Peer" исключение.

10-17 18:29:01.234: I / Система.out (4006): нет однорангового сертификата

должен ли я вручную загрузить мой сертификат CA как-то в этой реализации?

2 ответов


решено с помощью: HttpsURLConnection

URLConnection conn = null;
URL url = new URL(strURL);
conn = url.openConnection();
HttpsURLConnection httpsConn = (HttpsURLConnection) conn;

это, кажется, отлично работает с установленными пользователем сертификатами CA.


вы можете выполнить задачу также с помощью DefaultHttpClient, хотя здесь предлагается в:

предпочитают HttpURLConnection для нового кода

обратите внимание также при импорте или добавлении сертификата в приложение, так как у вас могут возникнуть проблемы с обновлением сертификата, когда он истечет.

вот как получить DefaultHttpClient самоподписанный сертификат:

 * This method returns the appropriate HttpClient.
 * @param isTLS Whether Transport Layer Security is required.
 * @param trustStoreInputStream The InputStream generated from the BKS keystore.
 * @param trustStorePsw The password related to the keystore.
 * @return The DefaultHttpClient object used to invoke execute(request) method.
private DefaultHttpClient getHttpClient(boolean isTLS, InputStream trustStoreInputStream, String trustStorePsw) 
    throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException, UnrecoverableKeyException {
    DefaultHttpClient client = null;        
    SchemeRegistry schemeRegistry = new SchemeRegistry();
    Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 8080);
    schemeRegistry.register(http);
    if(isTLS) {
        KeyStore trustKeyStore = null;
        char[] trustStorePswCharArray = null;
        if(trustStorePsw!=null) {
            trustStorePswCharArray = trustStorePsw.toCharArray();
        } 
        trustKeyStore = KeyStore.getInstance("BKS");
        trustKeyStore.load(trustStoreInputStream, trustStorePswCharArray);
        SSLSocketFactory sslSocketFactory = null;
        sslSocketFactory = new SSLSocketFactory(trustKeyStore);
        Scheme https = new Scheme("https", sslSocketFactory, 8443);
        schemeRegistry.register(https);
    }                
    HttpParams httpParams = new BasicHttpParams();
    HttpConnectionParams.setConnectionTimeout(httpParams, CONNECTION_TIMEOUT);
    HttpConnectionParams.setSoTimeout(httpParams, SOCKET_TIMEOUT);        
    ClientConnectionManager clientConnectionManager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);        
    client = new DefaultHttpClient(clientConnectionManager, httpParams);        
    return client;
}

а вот как получить HttpsURLConnection:

 * This method set the certificate for the HttpsURLConnection
 * @param url The url to contact.
 * @param certificateInputStream The InputStream generated from the .crt certificate.
 * @param certAlias The alias for the certificate. 
 * @return The returned HttpsURLConnection
private HttpsURLConnection getHttpsURLConnection(URL url, InputStream certificateInputStream, String certAlias) 
    throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
    HttpsURLConnection connection = null;
    CertificateFactory certFactory = null;
    Certificate cert = null;
    KeyStore keyStore = null;
    TrustManagerFactory tmFactory = null;
    SSLContext sslContext = null;
    // Load certificates from an InputStream
    certFactory = CertificateFactory.getInstance("X.509");
    cert = certFactory.generateCertificate(certificateInputStream);
    certificateInputStream.close();
    // Create a KeyStore containing the trusted certificates
    keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(null, null);
    keyStore.setCertificateEntry(certAlias, cert);
    // Create a TrustManager that trusts the certificates in our KeyStore
    tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmFactory.init(keyStore);
    // Create an SSLContext that uses our TrustManager
    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, tmFactory.getTrustManagers(), null);
    connection = (HttpsURLConnection)url.openConnection();
    connection.setSSLSocketFactory(sslContext.getSocketFactory());
    return connection;
}