Anulando el Administrador de confianza SSL en Android

Estoy intentando anular el administrador de confianza en Android. Quiero permitir que el administrador de confianza subyacente verifique los certificados, pero necesito determinar si un certificado ha expirado. Si el certificado está vencido, necesito ignorarlo y aceptar el certificado. Algunos dispositivos móviles restablecerán la fecha a una fecha anterior si se retira la batería, lo que hará que el certificado aparezca como si hubiera expirado. Mi aplicación debe continuar ejecutándose incluso si esto sucede.

El problema que estoy teniendo es que esta línea de código arroja una NullPointerException:

origTrustmanager.checkServerTrusted(certs, authType); 

De acuerdo con los documentos, checkServerTrusted nunca debe arrojar un NullPointerExeption. certs tiene dos elementos. authType está establecido en “RSA”. Si no implemento un administrador de confianza personalizado, se lanzará una excepción que indique claramente que el certificado ha expirado, por lo que sé que el administrador de confianza subyacente está haciendo su trabajo. Incluso si configuro la fecha y la hora en mi dispositivo para que estén dentro del tiempo de validez del certificado, la línea checkServerTrusted arriba genera una excepción. ¿Por qué? Claramente estoy haciendo algo mal. Aquí está el código para mi Administrador de confianza personalizado y cómo estoy accediendo a la 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; } } } 

Código para acceder a una 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()); 

Si nunca inicializa la variable de instancia origTrustmanager , tendrá su valor predeterminado de null , lo que de hecho causará un NPE cada vez que intente usarlo.

Acabo de editar mi respuesta anterior para mostrar un ejemplo de inicialización de TrustManager. (No lo he probado en Android, pero funciona bien en Java simple).

Tenga cuidado de no atrapar demasiado. Aquí, está capturando CertificateException y Exception en su administrador de confianza: esto es tan bueno como no tener nada, ya que estos métodos están destinados a arrojar esas excepciones. Asegúrese de capturar solo CertificateExpiredException si desea ignorar las fechas de caducidad.

Tenga en cuenta que esto es solo un truco que se basa en el hecho de que, en la práctica, la verificación del certificado se realiza después de la verificación general de la confianza (al menos en la implementación de OpenJDK). Hasta donde yo sé, no hay nada en las especificaciones que diga que la caducidad del certificado se verifica después . Se realizó antes de otra verificación en elementos de confianza e ignoró esa excepción, podría dejar más certificados de los deseados.

Usa este código. Esto funciona para mí

 TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {} public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {} public X509Certificate[] getAcceptedIssuers() { return null; } }; // Create a trust manager that does not validate certificate chains TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {} public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {} } }; SSLContext sslContext = null; try { sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[] { tm }, null); } catch (Exception e1) { e1.printStackTrace(); return; } AsyncSSLSocketMiddleware sslMiddleWare = Ion.getDefault(context).getHttpClient().getSSLSocketMiddleware(); sslMiddleWare.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); sslMiddleWare.setSSLContext(sslContext); Ion.getDefault(context).getHttpClient().getSSLSocketMiddleware().setTrustManagers(trustAllCerts); Ion.getDefault(context).getHttpClient().getSSLSocketMiddleware().setSSLContext(sslContext); Ion.with(context).load("POST", serverUrl) .setHeader("Content-Type", "application/json") .setHeader("Accept", "application/json") .setLogging("ION_LOGGING", Log.VERBOSE).setJsonObjectBody(json)