【问题标题】:How to solve javax.net.ssl.SSLHandshakeException Error without Google Play Services installed?如何在未安装 Google Play 服务的情况下解决 javax.net.ssl.SSLHandshakeException 错误?
【发布时间】:2019-05-24 15:57:42
【问题描述】:

我正在使用 Exoplayer 开发广播应用程序。 如果是 this 播客,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.通过调用HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl) 来使用 NetCipher 而不是 HttpUrlConnection,如here 所述

4.使用 NoSSLv3SocketFactory 就像描述的here

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.从here 下载 .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.仅使用 here 中的代码启用 TLSv1.2

我用于测试的设备是三星 SM-t111 Android 4.2.2。它安装了谷歌播放服务,但我试图在不使用谷歌播放服务的情况下解决这个问题,因为客户端的设备没有它。

请提出可行的解决方案?

【问题讨论】:

    标签: android ssl tls1.2 sslhandshakeexception httpsurlconnection


    【解决方案1】:

    就我而言,这是密码套件问题。要确定是否也是您的情况,您需要:

    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.2Cipher : ECDHE-RSA-AES256-GCM-SHA384

      密码套件是给定 SSL 连接使用的密码算法的组合。期间 在协商过程中,服务器和客户端必须就双方都可用的密码套件达成一致 环境。客户端向服务器发送支持的密码列表,服务器选择一个,然后 加密开始。如果没有这样的通用套件,则无法建立 SSL 连接,并且 没有数据可以交换。

    5. 转到ssl labs 并在主机名文本字段中输入您的主机名YOUR_HOST_NAME.com
    6. 出现服务器IP后点击它
    7. 找到握手模拟部分。就我而言,Android 4.2 并未在此处列出。

    为了理解为什么没有列出 Android 4.2,我找到了the list of all Cipher Suites supported by Android 4.2。我将服务器的密码套件与 Android 4.2 进行了比较,我没有发现它们之间有共同的密码套件。 我在official list of cipher suites supported by Android system 中搜索 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,他们说对于 API 级别 20+ 支持的密码套件(实际上是 API 级别 21 - Android 5.0,因为 API 级别 20 是 KITKAT_WATCH)。

    在我的情况下,如果没有适当的解决方案,它无法在客户端解决 服务器配置。 2.使用HTTP代替HTTPS是不可能的,因为播客使用了代理服务器,因为 其中我们没有播客中的最终链接。如果只是将 HTTPS 更改为 HTTP 的 重定向前的链接 - exoplayer 进入无限循环尝试打开连接。 3. 在没有 Google Play 的设备上,我们无法更新支持的密码套件列表。

    如果没有 Google Play 服务的 Android 设备上的密码套件问题可以在客户端解决并且您知道如何解决,请在下面添加答案或发表评论。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-22
      • 2014-03-13
      • 2011-10-03
      相关资源
      最近更新 更多