HttpClient и пользовательские TrustManager на Android - PullRequest
3 голосов
/ 02 марта 2011

Я пытался зарегистрировать свой собственный TrustManger в библиотеке apache HttpClient.Следующая ссылка содержит инструкции о том, как это сделать: Соединение Https Android

К сожалению, конструктор, который я хотел бы использовать (публичный SSLSocketFactory (SSLContext sslContext)), недоступен в версии AndroidHttpClient.Я бы использовал sslContext для инициализации моего пользовательского TrustManager.Похоже, Android заменил это на KeyStore.

Мой вопрос: (как) я могу зарегистрировать собственный TrustManger с DefaultHttpClient в Android?Есть ли где-нибудь альтернатива в классах KeyStore?

В конечном счете, я хотел бы пока игнорировать проверку сертификатов ... Пожалуйста, рассмотрите только библиотеку HttpClient, поскольку все мое приложение основано на ней.

Ответы [ 2 ]

3 голосов
/ 10 апреля 2014

Решение - создать собственную фабрику сокетов.

public class NetworkSSLSocketFactory implements LayeredSocketFactory {

    private SSLContext sslContext;
    private SSLSocketFactory socketFactory;
    private X509HostnameVerifier hostnameVerifier;

    /**
     * Creates a socket factory that will use the {@link SSLContext} and
     * {@link X509HostnameVerifier} specified. The SSLContext provided should
     * have the {@link NetworkTrustManager} associated with it.
     * 
     * @param sslContext
     * @param hostnameVerifier
     */
    public NetworkSSLSocketFactory(SSLContext sslContext,
            X509HostnameVerifier hostnameVerifier) {
        this.sslContext = sslContext;
        this.socketFactory = sslContext.getSocketFactory();
        this.hostnameVerifier = hostnameVerifier;
    }  
}

Затем создайте SSLContext, который использует ваш TrustManager, а затем создайте AndroidHttpClient и замените его схему https на схему, которая использует ваш SocketFactory.

    /**
     * Return the SSLContext for use with our HttpClient or create a new Context
     * if needed.
     * <p>
     * This context uses our {@link NetworkTrustManager}
     * 
     * @return an {@link SSLContext}
     */
    public SSLContext getSSLContext() {

        if (mSSLContextInstance != null)
            return mSSLContextInstance;

        try {
            mSSLContextInstance = SSLContext.getInstance("TLS");
            TrustManager trustManager = new NetworkTrustManager(getKeyStore());
            TrustManager[] tms = new TrustManager[] { trustManager };
            mSSLContextInstance.init(null, tms, new SecureRandom());
        } catch (NoSuchAlgorithmException e) {
            Log.e(TAG, e.getMessage());
        } catch (KeyManagementException e) {
            Log.e(TAG, e.getMessage());
        }

        return mSSLContextInstance;
    }

Теперь клиент

/**
 * Return an HttpClient using our {@link NetworkTrustManager} and
 * {@link NetworkHostnameVerifier}
 * 
 * @return an {@link HttpClient}
 */
public HttpClient getHttpClient() {

    if (mHttpClientInstance != null)
        return mHttpClientInstance;

    SSLContext sslContext = getSSLContext();

    // Now create our socket factory using our context.
    X509HostnameVerifier hostnameVerifier = new NetworkHostnameVerifier();
    NetworkSSLSocketFactory sslSocketFactory = new NetworkSSLSocketFactory(
            sslContext, hostnameVerifier);

    // Some services (like the KSOAP client) use the HttpsURLConnection
    // class
    // to establish SSL connections.
    HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
    HttpsURLConnection.setDefaultSSLSocketFactory(sslContext
            .getSocketFactory());

    // Generate the Client for the Server
    mHttpClientInstance = AndroidHttpClient.newInstance(getAgent(),
            mContext);

    // Get the registry from the AndroidHttpClient and change the
    // HTTPS scheme to use our socket factory. This way we can
    // control the certificate authority and trust system.
    SchemeRegistry schemeRegistry = mHttpClientInstance
            .getConnectionManager().getSchemeRegistry();

    schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));

    return mHttpClientInstance;
}

Если вы не знаете, как создать новое хранилище ключей, перейдите:

    /**
     * Get the current KeyStore or if not yet created, create a new one. This
     * will <b>NOT</b> load the KeyStore file identified by
     * {@link #KEYSTORE_NAME}. To load the KeyStore file, use the function
     * {@link #loadKeyStore()} which will automatically call this function (so
     * you don't need to).
     * <p>
     * 
     * @return a {@link KeyStore}
     */
    public KeyStore getKeyStore() {

        if (mKeyStore != null)
            return mKeyStore;

        try {
            String defaultType = KeyStore.getDefaultType();
            mKeyStore = KeyStore.getInstance(defaultType);
            mKeyStore.load(null, null);
        } catch (Exception e) {
            Log.w(TAG, e.getMessage());
        }

        return mKeyStore;
    }

Приведенное выше решение является началом решения, которое позволяет вам создать TrustManager, который будет проверять сертификаты в «System KeyStore», а также у вас есть «Private KeyStore» (два хранилища ключей). Затем вам не нужно пытаться добавить сертификаты в системный склад ключей. Вы можете создать свой собственный KeyStore в папке getFilesDir ().

У меня до сих пор нет законченной логики для захвата сертификата из HttpResult = HttpClient.execute (HttpPost); метод, но я сейчас активно пишу это. Если вам нужна помощь, я мог бы работать с вами сейчас.

Если кто-то знает, как перехватить / получить сертификат от SSLSocekt внутри объекта HttpRequestBase, пожалуйста, дайте мне знать. Я пытаюсь выследить это.

0 голосов
/ 23 февраля 2016

На самом деле, метод существует, но скрыт.Он используется внутри getHttpSocketFactory ().Я заставил это работать, просто используя отражение.Не безопасно, но хорошо подходит для разработки.

Class<org.apache.http.conn.ssl.SSLSocketFactory> c = org.apache.http.conn.ssl.SSLSocketFactory.class;
Constructor<org.apache.http.conn.ssl.SSLSocketFactory> ctor = c.getConstructor(javax.net.ssl.SSLSocketFactory.class);
SSLSocketFactory ssf = ctor.newInstance(SSLCertificateSocketFactory.getInsecure(getSSLHandshakeTimeout(), null));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...