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:
- Comportamiento de tipo navegador en certificados no válidos / autofirmados
- El certificado RapidSSL no es de confianza en la tableta Android
- Certificado ssl de android
- Autenticación de cliente SSL en Android 4.x
- Excepción terminada handshake de https de Android
- 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.
-
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(); }
-
Esto por alguna razón esto siempre genera un
SSLPeerUnverifiedException
con o sin el keystore. Y con o sin elCertificatePinner
.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?
- Si utilizo SSLSocket en Android y código duro, la contraseña del truststore en el código fuente es insegura?
- ¿Deshabilitar la validación del certificado SSL de la conexión HTTPS?
- ¿Es posible almacenar certificado SSL en android webview
- Implementación de TLS 1.2 en Android 2.3.3
- ¿Cómo se puede cargar https url sin el uso de ssl en android webview
- ¿Cómo habilitar un certificado autofirmado para sockets SSL en Android?
- Cómo hacer la reanudación de sesión SSL en Android
- El ancla de la confianza para la trayectoria del certificado no encontrada al usar sobre 3g pero trabaja muy bien sobre WiFi
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();
- Android: ¿Puedo activar / desactivar el filtro de intención de una actividad mediante programación?
- Descargar archivo a directorio personalizado