OkHttp javax.net.ssl.SSLPeerUnverifiedException: Nombre de host domain.com no verificado

Llevo días intentando que esto funcione. Estoy intentando conectarme a mi servidor sobre https con un certificado auto-firmado. No creo que haya páginas o ejemplos que no haya leído hasta ahora.

Que he hecho:

  1. Creado bks keystore siguiendo este tutorial: http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html

Utiliza openssl s_client -connect domain.com:443 para obtener el certificado del servidor. A continuación, crea un almacén de claves bks utilizando castillo hinchable.

  1. La lectura creó keystore de la carpeta cruda que la agregaba a sslfactory y entonces a OkHttpClient. Me gusta esto:

     public ApiService() { mClient = new OkHttpClient(); mClient.setConnectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS); mClient.setReadTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS); mClient.setCache(getCache()); mClient.setCertificatePinner(getPinnedCerts()); mClient.setSslSocketFactory(getSSL()); } protected SSLSocketFactory getSSL() { try { KeyStore trusted = KeyStore.getInstance("BKS"); InputStream in = Beadict.getAppContext().getResources().openRawResource(R.raw.mytruststore); trusted.load(in, "pwd".toCharArray()); SSLContext sslContext = SSLContext.getInstance("TLS"); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(trusted); sslContext.init(null, trustManagerFactory.getTrustManagers(), null); return sslContext.getSocketFactory(); } catch(Exception e) { e.printStackTrace(); } return null; } public CertificatePinner getPinnedCerts() { return new CertificatePinner.Builder() .add("domain.com", "sha1/theSha=") .build(); } 
  2. Esto por alguna razón esto siempre genera un SSLPeerUnverifiedException con o sin el keystore. Y con o sin el CertificatePinner .

     javax.net.ssl.SSLPeerUnverifiedException: Hostname domain.com not verified: 0 W/System.err﹕ certificate: sha1/theSha= W/System.err﹕ DN: 1.2.840.113549.1.9.1=#1610696e666f40626561646963742e636f6d,CN=http://domain.com,OU=development,O=domain,L=Valencia,ST=Valencia,C=ES W/System.err﹕ subjectAltNames: [] W/System.err﹕ at com.squareup.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:124) W/System.err﹕ at com.squareup.okhttp.Connection.connect(Connection.java:143) W/System.err﹕ at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:185) W/System.err﹕ at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128) W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341) W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:330) W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:248) W/System.err﹕ at com.squareup.okhttp.Call.getResponse(Call.java:273) W/System.err﹕ at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:230) W/System.err﹕ at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:201) W/System.err﹕ at com.squareup.okhttp.Call.execute(Call.java:81) ... 

¿Qué estoy haciendo mal?

Tuve el mismo problema, sin embargo, necesitaba mi aplicación para trabajar en varios entornos de puesta en escena, todos los cuales tenían auto cert firmado. Para empeorar las cosas, podrían cambiar esos certs sobre la marcha.

Para corregir esto, al conectarme a la puesta en escena solamente, agregué un SSLSocketFactory que confiaba en todos los certs. Esto arregló el error de java, sin embargo me dejó con la excepción okhttp anotada en este boleto.

Para evitar este error, necesité agregar una más personalización a mi okHttpClient. Esto arregló el error para mí.

 okHttpClient.setHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }); 

Finalmente conseguí esto trabajando con una mezcla de respuestas múltiples.

En primer lugar, los certificados se hizo de manera incorrecta, no estoy seguro de cómo. Pero al crearlos usando el script en esta respuesta les hizo funcionar. Lo que se necesitaba era un certificado de servidor y una clave. Entonces el cliente necesitaba otro certificado.

Para usar el certificado en android, convertí el archivo .pem en un archivo .crt como este:

 openssl x509 -outform der -in client.pem -out client.crt 

En android he añadido el certificado a mi cliente OkHttp como el siguiente:

 public ApiService() { mClient = new OkHttpClient(); mClient.setConnectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS); mClient.setReadTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS); mClient.setCache(getCache()); mClient.setSslSocketFactory(getSSL()); } protected SSLSocketFactory getSSL() { try { CertificateFactory cf = CertificateFactory.getInstance("X.509"); InputStream cert = getAppContext().getResources().openRawResource(R.raw.client); Certificate ca = cf.generateCertificate(cert); cert.close(); // creating a KeyStore containing our trusted CAs String keyStoreType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(null, null); keyStore.setCertificateEntry("ca", ca); return new AdditionalKeyStore(keyStore); } catch(Exception e) { e.printStackTrace(); } return null; } 

La última parte con la new AdditionalKeyStore() se toma de esta respuesta muy bien escrita . Que añade un almacén de claves de reserva.

Espero que esto podría ayudar a alguien más! Esta es la forma más sencilla de obtener HTTPS trabajando con un certificado auto-firmado que he encontrado. Otras maneras incluyen tener un BouncyCastle keystore que me parece excesivo.

Este problema se soluciona estableciendo setHostNameVerifier en okHttpBuilder . Asegúrese de que el método verify devuelva true.

Muestra:

 okHttpClient.setHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }); OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.hostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }); OkHttpClient client = builder.build(); 
  • ¿Cómo puedo hacer que Android Volley realice una solicitud HTTPS, utilizando un certificado autofirmado por una CA de Unkown?
  • Android - Https conexión a un servicio WCF de .NET da SSLException: "Ningún certificado de compañero"
  • HttpsUrlConnection con proxy
  • Apache HttpClient en Android produciendo CertPathValidatorException (IssuerName! = SubjectName)
  • Cómo llamar al servicio web https en Android
  • Cordova "release" se comporta de forma diferente a "debug" con respecto a SSL
  • Deshabilitar SSL como un protocolo en HttpsURLConnection
  • TLS con extensión de indicación de nombre de servidor (RFC 3546) en Android
  • Javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Ancla de confianza para la ruta de certificación no encontrada
  • Aceptar certificados SSL autofirmados-> donde configurar TrustManager predeterminado
  • Android - convertir la cadena de certificados pkcs12 al objeto de certificado x509 para bks keystore
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.