Как решить javax.net.ssl.SSLHandshakeException Ошибка без установленных сервисов Google Play? - PullRequest
0 голосов
/ 26 декабря 2018

Я работаю над приложением радио, использующим Exoplayer.В случае этого подкаста Exoplayer генерирует SSLHandshakeException.

Чтобы это исправить, я попытался:

1.Обновите провайдера безопасности с помощью установщика провайдера, позвонив по номеру ProviderInstaller.installIfNeededAsync.

    public class MainActivity extends Activity
    implements ProviderInstaller.ProviderInstallListener {

    private static final int ERROR_DIALOG_REQUEST_CODE = 1;

    private boolean mRetryProviderInstall;

    //Update the security provider when the activity is created.
    @Override
    protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     ProviderInstaller.installIfNeededAsync(this, this);
    }

    /**
     * This method is only called if the provider is successfully 
    updated (or is already up-to-date).
     */
    @Override
    protected void onProviderInstalled() {
     // Provider is up-to-date, app can make secure network calls.
    }

    /**
    * This method is called if updating fails; the error code indicates
    * whether the error is recoverable.
    */
    @Override
    protected void onProviderInstallFailed(int errorCode, Intent recoveryIntent) {
      GoogleApiAvailability availability = GoogleApiAvailability.getInstance();
    if (availability.isUserRecoverableError(errorCode)) {
      // Recoverable error. Show a dialog prompting the user to
      // install/update/enable Google Play services.
      availability.showErrorDialogFragment(
          this,
          errorCode,
          ERROR_DIALOG_REQUEST_CODE,
          new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
              // The user chose not to take the recovery action
              onProviderInstallerNotAvailable();
            }
          });
    } else {
      // Google Play services is not available.
      onProviderInstallerNotAvailable();
    }
  }

    @Override
    protected void onActivityResult(int requestCode, int resultCode,
      Intent data) {
      super.onActivityResult(requestCode, resultCode, data);
      if (requestCode == ERROR_DIALOG_REQUEST_CODE) {
        // Adding a fragment via GoogleApiAvailability.showErrorDialogFragment
        // before the instance state is restored throws an error. So instead,
        // set a flag here, which will cause the fragment to delay until
        // onPostResume.
        mRetryProviderInstall = true;
      }
    }

    /**
     * On resume, check to see if we flagged that we need to reinstall the provider.
     */
    @Override
    protected void onPostResume() {
      super.onPostResume();
       if (mRetryProviderInstall) {
        // We can now safely retry installation.
        ProviderInstaller.installIfNeededAsync(this, this);
      }
      mRetryProviderInstall = false;
    }

    private void onProviderInstallerNotAvailable() {
      // This is reached if the provider cannot be updated for some reason.
      // App should consider all HTTP communication to be vulnerable, 
      // and take appropriate action.
    }
  }

2.Замените https на http

В этом случае Exoplayer выдает исключение с кодом ошибки 308 (исключение перенаправления).

3.Используйте NetCipher вместо HttpUrlConnection, вызвав HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl), как описано здесь

4.Используйте NoSSLv3SocketFactory , как описано здесь

5.Отключите проверку сертификата SSL , позвонив по номеру

 private static void disableSSLCertificateChecking() {
  TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
  public X509Certificate[] getAcceptedIssuers() {
  return null;
 }

 @Override
 public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
  // Not implemented
 }

 @Override
 public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
 // Not implemented
 }
 } };

  try {
  SSLContext sc = SSLContext.getInstance("TLS");

  sc.init(null, trustAllCerts, new java.security.SecureRandom());

  HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
  } catch (KeyManagementException e) {
  e.printStackTrace();
  } catch (NoSuchAlgorithmException e) {
  e.printStackTrace();
  }
 }

6.Создать customTrust

Чтобы получить сертификаты, я запускаю команду open ssl:

OpenSSL> s_client -connect simplecast.com:443

7.Загрузите файл .crt с здесь и, как Google предлагает запустить

    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    InputStream caInput = new BufferedInputStream(new 
    FileInputStream("my_downloaded.crt"));
    Certificate ca;
     try {
       ca = cf.generateCertificate(caInput);
       System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
     } finally {
       caInput.close();
    }

    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);

    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);

    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, tmf.getTrustManagers(), null);

    // Tell the URLConnection to use a SocketFactory from our SSLContext
    HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
    urlConnection.setSSLSocketFactory(context.getSocketFactory());

8.Включите только TLSv1.2 , используя код из здесь

Устройство, которое я использую для тестирования, - Samsung SM-t111 Android 4.2.2.На нем установлены сервисы Google Play, но я пытаюсь решить проблему без использования сервисов Google Play, потому что на устройстве клиента его нет.

Подскажите, пожалуйста, какое должно быть рабочее решение?

1 Ответ

0 голосов
/ 09 января 2019

В моем случае это проблема Cipher Suites.Чтобы выяснить, является ли это также вашим случаем, вам необходимо:

  1. Запустить OpenSSL> s_client -connect YOUR_HOST_NAME.com:443
  2. Найти центр сертификации CN = COMODO RSA Certification Authority
  3. На устройстве Android перейдите наSettings > Security > Trusted credentials > System и проверьте, указан ли центр сертификации в качестве доверенного сертификата.COMODO - это хорошо известный центр сертификации, поэтому он указан там, что означает, что проблема не в сертификате.
  4. Найдите протокол и шифр.В моем случае Protocol : TLSv1.2 и Cipher : ECDHE-RSA-AES256-GCM-SHA384

    Набор шифров - это комбинация криптографических алгоритмов, используемых данным SSL-соединением.В процессе согласования сервер и клиент должны договориться о наборе шифров, который доступен в обеих средах.Клиент отправляет список поддерживаемых шифров на сервер, сервер выбирает один и шифрование запускается.Если такого общего набора нет, SSL-соединение не может быть установлено и данные не могут быть обменены.

  5. Перейдите в ssl labs и введите свое имя хоста YOUR_HOST_NAME.com в текстовое поле Hostname.
  6. После появления IP-адреса сервера нажмите на него
  7. Найти Моделирование рукопожатия раздел.В моем случае Android 4.2 там не был указан.

Чтобы понять, почему Android 4.2 там не указан, я нашел список всех Cipher Suites, поддерживаемых Android 4.2 .Я сравнил Cipher Suites сервера с Android 4.2 и не нашел общих Cipher Suites между ними.Я ищу TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 в официальном списке наборов шифров, поддерживаемых системой Android , и они говорят, что для этого набора шифров поддерживается уровень API 20+ (на самом деле это уровень API 21 - Android 5.0, потому что уровень API 20 - уровень API 20 - KITKAT_WATCH).

В моем случае проблема не может быть решена на стороне клиента без соответствующей конфигурации сервера.2. Использование HTTP вместо HTTPS невозможно, поскольку подкаст использует прокси-сервер, из-за чего у нас нет окончательной ссылки в подкасте.Если просто изменить HTTPS на HTTP ссылки до перенаправления - exoplayer входит в неопределенный цикл, пытаясь открыть соединение.3. На устройствах без Google Play мы не можем обновить список поддерживаемых Cipher Suites.

Если проблему Cipher Suite на устройстве Android без служб Google Play можно решить на стороне клиента, и вы знаете, как добавитьответьте ниже или оставьте комментарий.

...