覆盖Android中的SSL Trust Manager

And*_*Dev 5 ssl android

我试图覆盖Android中的信任管理器。我想让基础信任管理器检查证书,但是我需要确定证书是否过期。如果证书已过期,我需要忽略它并接受证书。如果取出电池,某些移动设备会将日期重置为旧日期,从而导致证书看起来好像过期了。即使发生这种情况,我的应用也必须继续保持运行状态。

我遇到的问题是,此行代码引发NullPointerException:

origTrustmanager.checkServerTrusted(certs, authType);
Run Code Online (Sandbox Code Playgroud)

根据文档,checkServerTrusted绝不应抛出NullPointerExeption。certs有两个项目。authType设置为“ RSA”。如果我没有实现自定义的信任管理器,则会抛出一个异常,该异常清楚地表明证书已过期,因此我知道底层的信任管理器正在执行其工作。即使我将设备上的日期和时间设置在证书的有效期内,上面的checkServerTrusted行也会生成异常。为什么?显然我做错了。这是我的自定义信任管理器的代码以及如何访问Url:

class SSLTrustManager
{
  private X509TrustManager origTrustmanager;

  public SSLTrustManager()
  {
    try
    {
      TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
      tmf.init((KeyStore) null);
      TrustManager[] trustManagers = tmf.getTrustManagers();
      this.origTrustmanager = (X509TrustManager) trustManagers[0];
    }
    catch (Exception ex)
    {
    }
  }

  public javax.net.ssl.SSLSocketFactory GetSocketFactory()
  {
    try
    {
      TrustManager[] wrappedTrustManagers = new TrustManager[] {
          new X509TrustManager()
          {
            public java.security.cert.X509Certificate[] getAcceptedIssuers()
            {
              return origTrustmanager.getAcceptedIssuers();
            }

            public void checkClientTrusted(X509Certificate[] certs, String authType)
            {
              try
              {
                origTrustmanager.checkClientTrusted(certs, authType);
              }
              catch (CertificateException e)
              {
              }
            }

            public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException
            {
              try
              {
                origTrustmanager.checkServerTrusted(certs, authType);
              }
              catch(Exception ex)
              {
              }
            }
          }
       };

      SSLContext sslContext = SSLContext.getInstance("SSL");
      sslContext.init(null, wrappedTrustManagers, new java.security.SecureRandom());
      javax.net.ssl.SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
      return sslSocketFactory;
    }
    catch (Exception ex)
    {
      return null;
    }
  }
}    
Run Code Online (Sandbox Code Playgroud)

访问网址的代码:

SSLTrustManager sslTrustManager = new SSLTrustManager();
HttpsURLConnection.setDefaultSSLSocketFactory(sslTrustManager.GetSocketFactory());

URL siteUrl = new URL(url);
HttpsURLConnection conn = (HttpsURLConnection) siteUrl.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);

DataOutputStream out = new DataOutputStream(conn.getOutputStream());
Run Code Online (Sandbox Code Playgroud)

Bru*_*uno 4

如果您从未初始化origTrustmanager实例变量,它将具有默认值null,这确实会在您尝试使用它时导致 NPE。

我刚刚编辑了之前的答案,以展示 TrustManager 初始化的示例。(我还没有在 Android 上尝试过,但它在纯 Java 中工作得很好。)

小心不要抓太多。在这里,您在信任管理器中捕获了CertificateExceptionand Exception:这与什么都没有一样好,因为这些方法旨在抛出这些异常。确保仅CertificateExpiredException在您想忽略过期日期时才捕获。

请注意,这只是一个技巧,它依赖于这样一个事实:在实践中,证书验证是在一般信任验证之后完成的(至少在 OpenJDK 实现中)。据我所知,规范中没有任何内容表明证书过期是. 它是在对信任元素进行其他验证之前完成的,并且您忽略了该异常,您可以让比您想要的更多的证书通过。