studio significa que not found for conexion certpathvalidatorexception certification certificado cert java android servlets ssl https

java - significa - Android: conexión HTTPS(SSL) con HttpsURLConnection



ssl pinning android (4)

Tengo 2 aplicaciones, una es Servlet / Tomcat Server y la otra es una aplicación de Android.

Quiero usar HttpURLConnection para enviar y recibir XML entre ambos.

Código:

private String sendPostRequest(String requeststring) { DataInputStream dis = null; StringBuffer messagebuffer = new StringBuffer(); HttpURLConnection urlConnection = null; try { URL url = new URL(this.getServerURL()); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setDoOutput(true); urlConnection.setRequestMethod("POST"); OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream()); out.write(requeststring.getBytes()); out.flush(); InputStream in = new BufferedInputStream(urlConnection.getInputStream()); dis = new DataInputStream(in); int ch; long len = urlConnection.getContentLength(); if (len != -1) { for (int i = 0; i < len; i++) if ((ch = dis.read()) != -1) { messagebuffer.append((char) ch); } } else { while ((ch = dis.read()) != -1) messagebuffer.append((char) ch); } dis.close(); } catch (Exception e) { e.printStackTrace(); } finally { urlConnection.disconnect(); } return messagebuffer.toString(); }

Ahora, necesito usar SSL para enviar los XML por seguridad.

Primero, uso Java Keytool para generar el archivo .keystore.

Keytool -keygen -alias tomcat -keyalg RSA

Luego puse el código XML en el archivo server.xml de Tomcat para usar SSL

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" keystoreFile="c:/Documents and Settings/MyUser/.keystore" keystorePass="password" clientAuth="false" sslProtocol="TLS" />

Luego, lo cambio a HttpURLConnection for HttpsURLConnection

private String sendPostRequest(String requeststring) { DataInputStream dis = null; StringBuffer messagebuffer = new StringBuffer(); HttpURLConnection urlConnection = null; //Conexion por HTTPS HttpsURLConnection urlHttpsConnection = null; try { URL url = new URL(this.getServerURL()); //urlConnection = (HttpURLConnection) url.openConnection(); //Si necesito usar HTTPS if (url.getProtocol().toLowerCase().equals("https")) { trustAllHosts(); //Creo la Conexion urlHttpsConnection = (HttpsURLConnection) url.openConnection(); //Seteo la verificacion para que NO verifique nada!! urlHttpsConnection.setHostnameVerifier(DO_NOT_VERIFY); //Asigno a la otra variable para usar simpre la mism urlConnection = urlHttpsConnection; } else { urlConnection = (HttpURLConnection) url.openConnection(); } //Do the same like up

y agrega un método trustAllHosts para confiar en cada servidor (no verifique ningún certificado)

private static void trustAllHosts() { X509TrustManager easyTrustManager = new X509TrustManager() { public void checkClientTrusted( X509Certificate[] chain, String authType) throws CertificateException { // Oh, I am easy! } public void checkServerTrusted( X509Certificate[] chain, String authType) throws CertificateException { // Oh, I am easy! } public X509Certificate[] getAcceptedIssuers() { return null; } }; // Create a trust manager that does not validate certificate chains TrustManager[] trustAllCerts = new TrustManager[] {easyTrustManager}; // Install the all-trusting trust manager try { SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { e.printStackTrace(); } }

Esos cambios funcionaron muy bien, pero no quiero confiar en cada servidor. Quiero usar mi archivo de almacén de claves para validar la conexión y usar SSL de la manera correcta. He leído mucho en Internet y he realizado muchas pruebas, pero no puedo entender lo que tengo que hacer y cómo hacerlo.

¿Puede alguien ayudarme?

Muchas gracias

Disculpa mi pobre ingles

------------------------- ACTUALIZACIÓN 2011/08/24 ------------------- ------------------------------

Bueno, todavía estoy trabajando en esto. Hice un nuevo método para configurar KeyStore, InputStream, etc.

El método se ve así:

private static void trustIFNetServer() { try { TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); KeyStore ks = KeyStore.getInstance("BKS"); InputStream in = context.getResources().openRawResource(R.raw.mykeystore); String keyPassword = "password"; ks.load(in, keyPassword.toCharArray()); in.close(); tmf.init(ks); TrustManager[] tms = tmf.getTrustManagers(); SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, tms, new java.security.SecureRandom()); } catch (Exception e) { e.printStackTrace(); } }

Primero tuve muchos problemas con la clave y el certificado, pero ahora está funcionando (creo)

Mi problema ahora mismo es una excepción de TimeOut. No sé por qué se genera. Creo que es algo con la escritura de datos, pero no puedo resolverlo todavía.

¿Alguna idea?


Debe crear un archivo de tienda de confianza para su certificado autofirmado como se describe aquí . Úselo en el lado del cliente para conectarse con su servidor. Realmente no importa si usas JKS u otro formato, por ahora asumiré JKS.

Para lograr lo que tiene en mente, necesita un TrustManager diferente, obviamente. Puede usar TrustManagerFactory y alimentar su configuración de confianza con su tienda de confianza recién creada.

TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); KeyStore ks = KeyStore.getInstance("JKS"); FileInputStream in = new FileInputStream("<path to your key store>"); ks.load(in, "password".toCharArray()); in.close(); tmf.init(ks); TrustManager[] tms = tmf.getTrustManagers();

Utilice tms para tms su SSLContext en su lugar para la nueva configuración de confianza que se utilizará para su conexión SSL / TLS.

También debe asegurarse de que la parte CN del certificado TLS del servidor sea igual al FQDN (nombre de dominio completo) de su servidor, por ejemplo, si la URL base de su servidor es '' https://www.example.com '', entonces la CN del certificado debe ser ''www.example.com''. Esto es necesario para la verificación de nombre de host, una función que evita los ataques de hombre en el medio. Puede desactivar esto, pero solo cuando lo use su conexión será realmente segura.


Crea tu tienda de confianza, almacena como activo y úsala para inicializar este SocketFactory . Luego use la fábrica en lugar de la suya propia.



Sería muy feliz si alguien se beneficia con el siguiente código que será útil para:
1) Usando HttpUrlConnection para hacer una solicitud simple.
2) Usando HttpsUrlConnection al confiar en todos los certificados.
3) Usando HttpsUrlConnection con certificado personalizado para llamadas seguras (Usando el archivo .bks)

---------------- Llame a estos métodos según sus requisitos --------------

import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.widget.TextView; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.security.KeyStore; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; public class MainActivity extends AppCompatActivity { TextView txtResult; public static final String TAG = MainActivity.class.getName(); public static final String SERVER_AUTH_URL = "https://demo.your.secure.ulr"; //Https i.e. Secure request String result = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); txtResult = (TextView)findViewById(R.id.txt_result); AsyncRequest asyncRequest = new AsyncRequest(); asyncRequest.execute(); } public class AsyncRequest extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { //result = sendGETRequestHttp(); //HttpUrlConnection request //result = sendGETRequestHttpsTrustAll(); //HttpsUrlConnection request, trust all built in certificate in device result = sendGETRequestHttpsWithCertificate(MainActivity.this); //request for secure connection with custom certificate return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); txtResult.setText(result); } } private String sendGETRequestHttp() { // String requestString (If have POST parameters) DataInputStream dis = null; StringBuffer messagebuffer = new StringBuffer(); HttpURLConnection urlConnection = null; try { URL url = new URL("http://www.yoururl.com/"); //Simple HttpURLConnection request urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setDoOutput(true); urlConnection.setRequestMethod("GET"); //("POST"); //OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream()); //out.write(requestString.getBytes()); //out.flush(); InputStream in = new BufferedInputStream(urlConnection.getInputStream()); dis = new DataInputStream(in); int ch; long len = urlConnection.getContentLength(); if (len != -1) { for (int i = 0; i < len; i++) if ((ch = dis.read()) != -1) { messagebuffer.append((char) ch); } } else { while ((ch = dis.read()) != -1) messagebuffer.append((char) ch); } dis.close(); } catch (Exception e) { e.printStackTrace(); } finally { urlConnection.disconnect(); } return messagebuffer.toString(); } private String sendGETRequestHttpsTrustAll() { // String requestString (If have POST parameters) DataInputStream dis = null; StringBuffer messagebuffer = new StringBuffer(); HttpURLConnection urlConnection = null; try { URL url = new URL(SERVER_AUTH_URL); //("https://www.codeproject.com/"); //Connection port HTTPS HttpsURLConnection urlHttpsConnection = null; if (url.getProtocol().toLowerCase().equals("https")) { trustAllHosts(); //Trust all certificate //Open Connection urlHttpsConnection = (HttpsURLConnection) url.openConnection(); //Set Verifier urlHttpsConnection.setHostnameVerifier(DO_NOT_VERIFY); //Assigning value urlConnection = urlHttpsConnection; } else { urlConnection = (HttpURLConnection) url.openConnection(); } urlConnection.setDoOutput(true); urlConnection.setRequestMethod("GET"); //("POST"); //OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream()); //out.write(requestString.getBytes()); //out.flush(); InputStream in = new BufferedInputStream(urlConnection.getInputStream()); dis = new DataInputStream(in); int ch; long len = urlConnection.getContentLength(); if (len != -1) { for (int i = 0; i < len; i++) if ((ch = dis.read()) != -1) { messagebuffer.append((char) ch); } } else { while ((ch = dis.read()) != -1) messagebuffer.append((char) ch); } dis.close(); } catch (Exception e) { e.printStackTrace(); } finally { urlConnection.disconnect(); } return messagebuffer.toString(); } private static void trustAllHosts() { X509TrustManager easyTrustManager = 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[]{easyTrustManager}; // Install the all-trusting trust manager try { SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { e.printStackTrace(); } } final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }; private String sendGETRequestHttpsWithCertificate(Context context){ // String requestString (If have POST parameters) DataInputStream dis = null; StringBuffer messagebuffer = new StringBuffer(); HttpsURLConnection urlConnection = null; try{ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); KeyStore ks = KeyStore.getInstance("BKS"); InputStream in = context.getResources().openRawResource(R.raw.yourtruststore); //.bks file in raw folder of resources String keyPassword = "pass"; //Your Password for cetificate ks.load(in, keyPassword); in.close(); tmf.init(ks); TrustManager[] tms = tmf.getTrustManagers(); SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, tms, new java.security.SecureRandom()); sc.init(null, tmf.getTrustManagers(), null); // Tell the URLConnection to use a SocketFactory from our SSLContext URL url = new URL(SERVER_AUTH_URL); urlConnection = (HttpsURLConnection) url.openConnection(); urlConnection.setSSLSocketFactory(sc.getSocketFactory()); urlConnection.setDoOutput(true); urlConnection.setRequestMethod("GET"); //("POST"); //OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream()); //out.write(requestString.getBytes()); //out.flush(); InputStream inStream = new BufferedInputStream(urlConnection.getInputStream()); dis = new DataInputStream(inStream); int ch; long len = urlConnection.getContentLength(); if (len != -1) { for (int i = 0; i < len; i++) if ((ch = dis.read()) != -1) { messagebuffer.append((char) ch); } } else { while ((ch = dis.read()) != -1) messagebuffer.append((char) ch); } dis.close(); } catch (Exception e) { Log.d(TAG,"Connection error = "+e.getMessage()); e.printStackTrace(); } finally { urlConnection.disconnect(); } return messagebuffer.toString(); } }