如何在未安装Google Play服务的情况下解决javax.net.ssl.SSLHandshakeException错误?

时间:2018-12-26 11:04:07

标签: android ssl tls1.2 sslhandshakeexception httpsurlconnection

我正在使用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。通过像描述here

那样调用HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl)来使用NetCipher 而不是HttpUrlConnection

4。使用here

中所述的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。从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

我用于测试的设备是Samsung SM-t111 Android 4.2.2。它已安装了Google Play服务,但由于客户端的设备没有安装此服务,因此我尝试不使用Google Play服务来解决此问题。

请提出什么可行的解决方案?

1 个答案:

答案 0 :(得分:0)

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

  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,因为Podcast使用Proxy服务器,因为   其中,播客中没有最终链接。如果只是将HTTPS更改为HTTP   重定向前链接-exoplayer进入无限循环尝试打开连接。   3.在没有Google Play的设备上,我们无法更新支持的密码套件的列表。

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