Поддерживает ли поддержка OkHttp самоподписанные сертификаты SSL?

Я работаю для клиента, у которого есть сервер с самоподписанным сертификатом SSL.

Я использую Retrofit + CustomClient, используя завершенный клиент OkHttp:

RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(Config.BASE_URL + Config.API_VERSION) .setClient(new CustomClient(new OkClient(), context)) .build(); 

Поддерживает ли OkHttp поддержку самоподписанного SSL-сервера сертификации по умолчанию?

Кстати. Какой клиент использует «Дооснащение» по умолчанию? Я думал, что это OkHttp, но когда я исследовал немного больше, я понял, что мне нужно импортировать зависимости OkHttp

    Да.

    «Дооснащение» позволяет настроить пользовательский HTTP-клиент, который настроен на ваши нужды.

    Что касается самоподписанных сертификатов SSL, здесь есть обсуждение. Ссылка содержит примеры кода для добавления самоподписанного SLL в DefaultHttpClient Android и для загрузки этого клиента в «Дооснащение».

    Если вам нужен OkHttpClient для принятия самоподписанного SSL, вам необходимо передать его пользовательский экземпляр setSslSocketFactory(SSLSocketFactory sslSocketFactory) помощью setSslSocketFactory(SSLSocketFactory sslSocketFactory) .

    Самый простой способ получить фабрику сокетов – получить один из javax.net.ssl.SSLContext как описано здесь .

    Ниже приведен пример настройки OkHttpClient:

     OkHttpClient client = new OkHttpClient(); KeyStore keyStore = readKeyStore(); //your method to obtain KeyStore SSLContext sslContext = SSLContext.getInstance("SSL"); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, "keystore_pass".toCharArray()); sslContext.init(keyManagerFactory.getKeyManagers(),trustManagerFactory.getTrustManagers(), new SecureRandom()); client.setSslSocketFactory(sslContext.getSocketFactory()); 

    Обновлен код для okhttp3 (с использованием построителя):

      OkHttpClient client = new OkHttpClient.Builder() .sslSocketFactory(sslContext.getSocketFactory()) .build(); 

    теперь client настроен на использование сертификатов из вашего KeyStore . Однако он будет доверять только сертификатам в вашем KeyStore и не будет доверять чему-либо еще, даже если ваша система доверяет им по умолчанию. (Если у вас есть только собственные сертификаты в вашем KeyStore и попытайтесь подключиться к главной странице Google через HTTPS, вы получите SSLHandshakeException ).

    Вы можете получить экземпляр KeyStore из файла, как показано в документах :

     KeyStore readKeyStore() { KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); // get user password and file input stream char[] password = getPassword(); java.io.FileInputStream fis = null; try { fis = new java.io.FileInputStream("keyStoreName"); ks.load(fis, password); } finally { if (fis != null) { fis.close(); } } return ks; } 

    Если вы находитесь на android, вы можете поместить его в папку res/raw и получить его из экземпляра Context используя

     fis = context.getResources().openRawResource(R.raw.your_keystore_filename); 

    Существует несколько дискуссий о том, как создать хранилище ключей. Например здесь

    Для okhttp3.OkHttpClient Version com.squareup.okhttp3: okhttp: 3.2.0 вы должны использовать следующий код:

     import okhttp3.Call; import okhttp3.Cookie; import okhttp3.CookieJar; import okhttp3.Headers; import okhttp3.HttpUrl; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; ...... OkHttpClient.Builder clientBuilder = client.newBuilder().readTimeout(LOGIN_TIMEOUT_SEC, TimeUnit.SECONDS); boolean allowUntrusted = true; if ( allowUntrusted) { Log.w(TAG,"**** Allow untrusted SSL connection ****"); final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { X509Certificate[] cArrr = new X509Certificate[0]; return cArrr; } @Override public void checkServerTrusted(final X509Certificate[] chain, final String authType) throws CertificateException { } @Override public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException { } }}; SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); clientBuilder.sslSocketFactory(sslContext.getSocketFactory()); HostnameVerifier hostnameVerifier = new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { Log.d(TAG, "Trust Host :" + hostname); return true; } }; clientBuilder.hostnameVerifier( hostnameVerifier); } final Call call = clientBuilder.build().newCall(request); 

    Два метода из нашего приложения, чтобы получить экземпляр OkHttpClient 3.0, который распознает ваши самозаверяющие сертификаты из вашего хранилища ключей (использует подготовленный файл сертификата pkcs12 в папке с исходными ресурсами вашего проекта Android):

     private static OkHttpClient getSSLClient(Context context) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, CertificateException, IOException { OkHttpClient client; SSLContext sslContext; SSLSocketFactory sslSocketFactory; TrustManager[] trustManagers; TrustManagerFactory trustManagerFactory; X509TrustManager trustManager; trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(readKeyStore(context)); trustManagers = trustManagerFactory.getTrustManagers(); if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers)); } trustManager = (X509TrustManager) trustManagers[0]; sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[]{trustManager}, null); sslSocketFactory = sslContext.getSocketFactory(); client = new OkHttpClient.Builder() .sslSocketFactory(sslSocketFactory, trustManager) .build(); return client; } /** * Get keys store. Key file should be encrypted with pkcs12 standard. It can be done with standalone encrypting java applications like "keytool". File password is also required. * * @param context Activity or some other context. * @return Keys store. * @throws KeyStoreException * @throws CertificateException * @throws NoSuchAlgorithmException * @throws IOException */ private static KeyStore readKeyStore(Context context) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException { KeyStore keyStore; char[] PASSWORD = "12345678".toCharArray(); ArrayList certificates; int certificateIndex; InputStream certificate; certificates = new ArrayList<>(); certificates.add(context.getResources().openRawResource(R.raw.ssl_pkcs12)); keyStore = KeyStore.getInstance("pkcs12"); for (Certificate certificate : certificates) { try { keyStore.load(certificate, PASSWORD); } finally { if (certificate != null) { certificate.close(); } } } return keyStore; } 

    Against Retrofit 1.9 Я смог принять любой сертификат со следующей страtagsей: использовать на свой страх и риск! Принятие любого сертификата опасно, и вы должны понимать последствия. Некоторые релевантные части поступают из org.apache.http.ssl , поэтому здесь вам может потребоваться импорт.

     // ... Client httpClient = getHttpClient(); RestAdapter adapter = new RestAdapter.Builder() .setClient(httpClient) // ... the rest of your builder setup .build(); // ... private Client getHttpClient() { try { // Allow self-signed (and actually any) SSL certificate to be trusted in this context TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true; SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom() .loadTrustMaterial(null, acceptingTrustStrategy) .build(); sslContext.getSocketFactory(); SSLSocketFactory sf = sslContext.getSocketFactory(); OkHttpClient client = new OkHttpClient(); client.setSslSocketFactory(sf); return new OkClient(client); } catch (Exception e) { throw new RuntimeException("Failed to create new HTTP client", e); } } 

    Следующий fragment кода позволяет создать клиент OkHttp, который можно использовать с помощью Retrofit. Ответ Mailmustdie «лучше» в том смысле, что он более безопасен, но снимок кода ниже выполняется быстрее

     import com.squareup.okhttp.Headers; import com.squareup.okhttp.MediaType; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.ResponseBody; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import okio.BufferedSink; import retrofit.client.Header; import retrofit.client.OkClient; import retrofit.client.Request; import retrofit.client.Response; import retrofit.mime.TypedInput; import retrofit.mime.TypedOutput; import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; public class TrustingOkClient extends OkClient { static final int CONNECT_TIMEOUT_MILLIS = 15 * 1000; // 15s static final int READ_TIMEOUT_MILLIS = 20 * 1000; // 20s private static OkHttpClient generateDefaultOkHttp() { OkHttpClient client = new OkHttpClient(); client.setConnectTimeout(CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); client.setReadTimeout(READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); final TrustManager[] certs = new TrustManager[]{new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkServerTrusted(final X509Certificate[] chain, final String authType) throws CertificateException { } @Override public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException { } }}; SSLContext ctx = null; try { ctx = SSLContext.getInstance("TLS"); ctx.init(null, certs, new SecureRandom()); } catch (final java.security.GeneralSecurityException ex) { } try { final HostnameVerifier hostnameVerifier = new HostnameVerifier() { @Override public boolean verify(final String hostname, final SSLSession session) { return true; } }; client.setHostnameVerifier(hostnameVerifier); client.setSslSocketFactory(ctx.getSocketFactory()); } catch (final Exception e) { } return client; } private final OkHttpClient client; public TrustingOkClient() { this(generateDefaultOkHttp()); } public TrustingOkClient(OkHttpClient client) { if (client == null) throw new NullPointerException("client == null"); this.client = client; } @Override public Response execute(Request request) throws IOException { return parseResponse(client.newCall(createRequest(request)).execute()); } static com.squareup.okhttp.Request createRequest(Request request) { com.squareup.okhttp.Request.Builder builder = new com.squareup.okhttp.Request.Builder() .url(request.getUrl()) .method(request.getMethod(), createRequestBody(request.getBody())); List
    headers = request.getHeaders(); for (int i = 0, size = headers.size(); i < size; i++) { Header header = headers.get(i); String value = header.getValue(); if (value == null) value = ""; builder.addHeader(header.getName(), value); } return builder.build(); } static Response parseResponse(com.squareup.okhttp.Response response) { return new Response(response.request().urlString(), response.code(), response.message(), createHeaders(response.headers()), createResponseBody(response.body())); } private static RequestBody createRequestBody(final TypedOutput body) { if (body == null) { return null; } final MediaType mediaType = MediaType.parse(body.mimeType()); return new RequestBody() { @Override public MediaType contentType() { return mediaType; } @Override public void writeTo(BufferedSink sink) throws IOException { body.writeTo(sink.outputStream()); } @Override public long contentLength() { return body.length(); } }; } private static TypedInput createResponseBody(final ResponseBody body) { try { if (body.contentLength() == 0) { return null; } return new TypedInput() { @Override public String mimeType() { MediaType mediaType = body.contentType(); return mediaType == null ? null : mediaType.toString(); } @Override public long length() { try { return body.contentLength(); } catch (Exception exception) { System.out.println(exception.toString()); } throw new Error("createResponseBody has invalid length for its response"); } @Override public InputStream in() throws IOException { return body.byteStream(); } }; } catch (Exception exception) { System.out.println(exception.toString()); } throw new Error("createResponseBody has invalid content length for its response"); } private static List
    createHeaders(Headers headers) { int size = headers.size(); List
    headerList = new ArrayList
    (size); for (int i = 0; i < size; i++) { headerList.add(new Header(headers.name(i), headers.value(i))); } return headerList; } }
    Давайте будем гением компьютера.