重写SSL信任管理器在Android中重写、管理器、SSL、Android

2023-09-12 08:18:55 作者:什么也不是。

我想重写信任管理器的Andr​​oid。我要让底层的信任管理器检查证书,但我需要确定一个证书已过期。如果证书已过期,我需要忽略它,并接受证书。一些移动设备将如果电池被移除的时间复位到一个老的日期,使得证书显示为虽然它已过期。我的应用程序必须继续保持运行,即使出现这种情况。

我遇到的问题是,这行code抛出一个NullPointerException异常:

  origTrustmanager.checkServerTrusted(证书,的authType);
 

根据文档,checkServerTrusted不应该抛出一个NullPointerExeption。证书中有两项。的authType设置为RSA。如果我没有实现自定义信任管理器,将引发异常,清楚地表明证书已经过期,所以我知道底层的信托经理正在做的工作。即使我设定的日期和时间,我的设备上是证书的有效期时间内,该checkServerTrusted线以上产生异常。为什么?显然,我做错了什么。这里是$ C $下我自定义信任管理器,以及如何我访问网址:

 类SSLTrustManager
{
  私人X509TrustManager origTrustmanager;

  公共SSLTrustManager()
  {
    尝试
    {
      的TrustManagerFactory TMF = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
      tmf.init((密钥库)NULL);
      的TrustManager [] trustManagers = tmf.getTrustManagers();
      this.origTrustmanager =(X509TrustManager)trustManagers [0];
    }
    赶上(例外前)
    {
    }
  }

  公共javax.net.ssl​​.SSLSocketFactory在getSocketFactory()
  {
    尝试
    {
      的TrustManager [] wrappedTrustManagers =新的TrustManager [] {
          新X509TrustManager()
          {
            公共java.security.cert.X509Certificate [] getAcceptedIssuers()
            {
              返回origTrustmanager.getAcceptedIssuers();
            }

            公共无效checkClientTrusted(x509证书[]证书,字符串的authType)
            {
              尝试
              {
                origTrustmanager.checkClientTrusted(证书,的authType);
              }
              赶上(CertificateException E)
              {
              }
            }

            公共无效checkServerTrusted(x509证书[]证书,字符串的authType)抛出CertificateException
            {
              尝试
              {
                origTrustmanager.checkServerTrusted(证书,的authType);
              }
              赶上(例外前)
              {
              }
            }
          }
       };

      的SSL连接的SSL连接= SSLContext.getInstance(SSL);
      sslContext.init(NULL,wrappedTrustManagers,新java.security.SecureRandom中的());
      javax.net.ssl​​.SSLSocketFactory的SSLSocketFactory = sslContext.getSocketFactory();
      返回SSLSocketFactory的;
    }
    赶上(例外前)
    {
      返回null;
    }
  }
}
 

$ C $下访问网址:

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

URL SITEURL =新的网址(URL);
HttpsURLConnection康恩=(HttpsURLConnection)siteUrl.openConnection();
conn.setRequestMethod(POST);
conn.setDoOutput(真正的);
conn.setDoInput(真正的);

DataOutputStream类OUT =新DataOutputStream类(conn.getOutputStream());
 
android应用程序是什么,简述Android应用程序结构是什么 公共题库

解决方案

如果你从来没有初始化 origTrustmanager 实例变量,它会空,这确实会造成NPE你想使用它的任何时间。

我刚刚编辑在此我previous答案显示的TrustManager初始化的一个例子。 (我还没有尝试在Android上,但它工作正常,在普通的Java。)

小心不要碰到太多。在这里,你捕 CertificateException 在你的信任管理器异常:这是不如有什么,因为这些方法是为了抛出这些异常。确保你唯一的缺点 CertificateExpiredException 如果你想忽略截止日期。

请注意,这只是,经过依赖于一个事实是,在实践中,证书验证完成后的一招的普遍信任验证(至少在OpenJDK的实现)。据我所知,没有什么在规格上,指出该证书过期的在的验证。据其他核查以前做过信任的元素,你忽略了异常,您可以通过比你希望让更多的证书。

I am trying to override the trust manager in Android. I want to let the underlying trust manager check certificates but I need to determine if a certificate is expired. If the certificate is expired, I need to ignore it and accept the certificate. Some mobile devices will reset the date to an old date if the battery is removed, causing the certificate to appear as though it expired. My app must continue to keep running even if this happens.

The problem I am having is that this line of code throws a NullPointerException:

origTrustmanager.checkServerTrusted(certs, authType);

According to the docs, checkServerTrusted should never throw a NullPointerExeption. certs has two items in it. authType is set to "RSA". If I don't implement a custom Trust Manager, an exception will be thrown that clearly indicates that the certificate has expired, so I know that the underlying Trust Manager is doing its job. Even if I set the date and time on my device to be within the validity time of the certificate, the checkServerTrusted line above generates an exception. Why? Clearly I'm doing something wrong. Here is the code for my custom Trust Manager and how I am accessing the 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;
    }
  }
}    

Code for accessing a url:

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());

解决方案

If you never initialise the origTrustmanager instance variable, it will have its default value of null, which will indeed cause an NPE any time you're trying to use it.

I've just edited my previous answer on this to show an example of TrustManager initialisation. (I haven't tried on Android, but it works fine in plain Java.)

Be careful not to catch too much. Here, you're catching CertificateException and Exception in your trust manager: this is as good as having nothing, since these methods are meant to throw those exceptions. Make sure you only catch CertificateExpiredException if you want to ignore expiration dates.

Note that this is only a trick that relies on the fact that, in practice, the certificate verification is done after the general trust verification (at least in the OpenJDK implementation). As far as I know, there's nothing in the specifications that says that the certificate expiration is verified after. It was done before other verification on elements of trust and you ignored that exception, you could let more certificate through than you want.

 
精彩推荐