2017-02-17 5 views
1

Я пытаюсь подключить самозаверяющий сертификат моего сервера. Мой OkHttpClient принимает два параметра, первый из них является SSL Оправа Factory:Okhttp3 - Принять все сертификаты и использовать сертификатPinner

final TrustManager[] trustAllCerts = new TrustManager[] { 
     new X509TrustManager() { 
      @SuppressLint("TrustAllX509TrustManager") 
      @Override 
      public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {} 

      @SuppressLint("TrustAllX509TrustManager") 
      @Override 
      public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {} 

      @Override 
      public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
        return new X509Certificate[0]; 
      } 
     } 
    }; 

// Install the all-trusting trust manager 
SSLContext sslContext; 
try { 
    sslContext = SSLContext.getInstance("SSL"); 
    sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); 
} catch (NoSuchAlgorithmException | KeyManagementException e) { 
    e.printStackTrace(); 
    FirebaseCrash.report(e); 
    return null; 
} 

// Create an ssl socket factory with our all-trusting manager 
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); 

Во-вторых, сертификат передник:

new CertificatePinner.Builder() 
    .add("bogus.com", "sha1/BOGUS") 
    .build() 

Примечание: если я не добавить certificatePinner, то все работает хорошо. Проблема заключается в том, что, когда запрос запускается на выполнение, CertificatePinner.check() вызывается:

if (pins.isEmpty()) return; 

Очевидно, что если я установил (непустое) certificatePinner, метод не будет останавливаться на достигнутом и будет продолжать. Затем следует проверить, что «по крайней мере один из сертификатов, закрепленных за моим именем хоста, является доверенным сертификатом».

Проблема заключается в том, что я передал пустой массив в getAcceptedIssuers для моего TrustManager - это означает, что самозаверяющий сертификат вызовет исключение, поскольку он явно не доверял «getAcceptedIssues». Похоже, что невозможно связать сертификат, которому явно не доверяют в «getAcceptedIssuers».

Есть ли способ обойти это? Это по дизайну?

Это, как я строю мой OkHttpClient:

OkHttpClient client = new OkHttpClient.Builder() 
    .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]) 
    .certificatePinner(certPinner) 
    .readTimeout(10, TimeUnit.SECONDS) 
    .connectTimeout(10, TimeUnit.SECONDS) 
    .build(); 

ответ

2

В TrustManager, CertificatePinner и проверка Hostname все делать разные, но важные вещи. Если вы хотите использовать самозаверяющие сертификаты, но по-прежнему имеете безопасность, в отличие от самоподписанных сертификатов исключительно для удобства локального развития, то вы, вероятно, захотите создать действительный TrustManager.

например. https://github.com/yschimke/oksocial/blob/3757196cde420b9d0fe37cf385b66f4cdafb1ae1/src/main/java/com/baulsupp/oksocial/security/CertificateUtils.java#L19

public static X509TrustManager load(List<File> serverCerts) 
     throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException { 
    return trustManagerForKeyStore(keyStoreForCerts(serverCerts)); 
    } 

    public static X509TrustManager trustManagerForKeyStore(KeyStore ks) 
     throws NoSuchAlgorithmException, KeyStoreException { 
    TrustManagerFactory tmf = 
     TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 

    tmf.init(ks); 

    return (X509TrustManager) tmf.getTrustManagers()[0]; 
    } 

    public static KeyStore keyStoreForCerts(List<File> serverCerts) 
     throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException { 
    CertificateFactory cf = CertificateFactory.getInstance("X.509"); 

    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); 
    ks.load(null); 

    for (int i = 0; i < serverCerts.size(); i++) { 
     try (InputStream is = new FileInputStream(serverCerts.get(i))) { 
     X509Certificate caCert = (X509Certificate) cf.generateCertificate(is); 
     ks.setCertificateEntry("cacrt." + i, caCert); 
     } 
    } 
    return ks; 
    } 

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

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

+0

Код, который вы предоставили, определенно помог мне, хотя это не совсем соответствует моему первоначальному вопросу. Благодаря вашей помощи я действительно создал действительный TrustManager. – geecko

+0

Да, я пытался ответить на то, что, как я думал, вы пытаетесь сделать, добавить самозаверяющий сертификат, чтобы у вас было безопасное соединение, но специально для этого. Принятие всех сертификатов, а затем попытка подключения, не похоже на типичный вариант использования. –

1
private static OkHttpClient getUnsafeOkHttpClient() { 
    try { 
    // Create a trust manager that does not validate certificate chains 
    final TrustManager[] trustAllCerts = new TrustManager[] { 
     new X509TrustManager() { 
      @Override 
      public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { 
      } 

      @Override 
      public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { 
      } 

      @Override 
      public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
      return new java.security.cert.X509Certificate[]{}; 
      } 
     } 
    }; 

    // Install the all-trusting trust manager 
    final SSLContext sslContext = SSLContext.getInstance("SSL"); 
    sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); 
    // Create an ssl socket factory with our all-trusting manager 
    final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); 

    OkHttpClient.Builder builder = new OkHttpClient.Builder(); 
    builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]); 
    builder.hostnameVerifier(new HostnameVerifier() { 
     @Override 
     public boolean verify(String hostname, SSLSession session) { 
     return true; 
     } 
    }); 

    OkHttpClient okHttpClient = builder 
     .connectTimeout(15, TimeUnit.SECONDS) 
     .writeTimeout(15, TimeUnit.SECONDS) 
     .readTimeout(15, TimeUnit.SECONDS) 
     .build(); 
    return okHttpClient; 
    } catch (Exception e) { 
    throw new RuntimeException(e); 
    } 
} 
+0

Хотя этот ответ, вероятно, правильный и полезный, рекомендуется, если вы [включите некоторое объяснение вместе с ним] (http://meta.stackexchange.com/q/114762/159034), чтобы объяснить, как это помогает решить проблему. Это становится особенно полезным в будущем, если есть изменения (возможно, не связанные), которые заставляют его перестать работать, а читатели должны понимать, как он работал. –

+0

@KevinBrown Вы правы, просто хотели помочь, но действительно расстроены ребятами здесь. – samcpp

+2

нужен образец кода для OkHttp3 – Lunatikul

Смежные вопросы