2012-09-10 15 views
8

Tengo problemas con la obtención de Android para conectarse a un servidor simple OpenSSL utilizando el objeto HttpsUrlConnection (he peinado a través Stackoverflow y una un montón de tutoriales en línea, y seguí los ejemplos más o menos línea por línea y todavía no puedo entender por qué el mío está roto cuando uso mi almacén de confianza local).Android HttpsURLConnection javax.net.ssl.SSLException Conexión cerrada por error pares apretón de manos cuando se utiliza almacén de confianza local de

Actualmente tengo una actividad Android que intenta conectarse a un simple OpenSSL server (puedo conectar con el servidor usando un cliente de OpenSSL), una vez que el HttpsUrlConnection.connect() se llama recibo una "javax.net.ssl.SSLException: Connection closed by peer" error during the SSL handshake. Tal vez yo soy la creación de mi servidor muestra de forma incorrecta ?

a tener en cuenta:

  • sin autorización del cliente en el momento
  • soy capaz de conectarse a https://www.google.com al cargar almacén de confianza predeterminado
  • no soy capaz de conectar con el servidor en el servidor local con el certificado autofirmado
  • no quieren confiar en todos los certificados
  • no quieren utilizar Apache HttpClient
  • quieren usar almacén de confianza local solamente
  • creados locales almacén de confianza con castillo hinchable
  • soy capaz de cargar correctamente almacén de confianza en
  • detrás de un firewall proxy, proxy está configurado en mi dispositivo virtual Android
  • AVD establece en Android 4.1 API 16.

cosas que ya he intentado:

  • que conecta a ambos 127.0.0.1 and 10.0.2.2
  • usando un nuevo SecureRandom() with the SSLContext.init()
  • crear la URL con 'URL u = new URL("https", "10.0.2.2", 443, "/");'
  • usando TrustManagerFactory.getDefaultAlgorithms() en lugar de la "X 509"
    • da "Unexpected response code error 503" lugar de "Conexión cerrada por el par"

Gracias de antemano por tomarse el tiempo para revisar mi pregunta!

servidor simple comenzó con el comando:

$ sudo openssl s_server -accept 443 -cert server-cert.pem -key server-key.pem -pass file:passphrase.txt -state -www -verify 0 

la conexión del cliente probado con el comando:

$ openssl s_client -connect 127.0.0.1:443 

código de actividad Android (editado para eliminar el código de ejecución completa de simplificación - por favor, hágamelo saber si hay más código es necesario) - la salida de error está debajo del código.

try { 
     TrustManagerFactory tmf; 

     // local trust store 
     tmf = TrustManagerFactory.getInstance("X509"); 
     tmf.init(loadLocalKeyStore(getApplicationContext())); 

     // default trust store - works for https://www.google.com 
     // tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
     // tmf.init((KeyStore) null); 

     SSLContext context = SSLContext.getInstance("TLS"); 
     context.init(null, tmf.getTrustManagers(), null); 

     HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.STRICT_HOSTNAME_VERIFIER; 
     URL u = new URL("https://10.0.2.2"); 

     HttpsURLConnection urlConnection = (HttpsURLConnection) u.openConnection(); 

     urlConnection.setSSLSocketFactory(context.getSocketFactory()); 
     urlConnection.setHostnameVerifier(hostnameVerifier); 
     urlConnection.connect(); 

     System.out.println("Response Code: " + urlConnection.getResponseCode()); 
     System.out.println("Response Code: " + urlConnection.getCipherSuite()); 
    } 

    ... 

    private KeyStore loadLocalKeyStore(Context context) { 
     InputStream in = context.getResources().openRawResource(R.raw.newserverkeystore); 
     KeyStore trusted = null; 
     try { 
      trusted = KeyStore.getInstance("BKS"); 
      trusted.load(in, "thisisasecret".toCharArray()); 
     } finally { 
      in.close(); 
     } 
     return trusted; 
    } 

de salida cuando se conecta correctamente a https://www.google.com:

09-09 21:58:09.947: I/System.out(669): Response Code: 200 
09-09 21:58:09.947: I/System.out(669): Response Code: TLS_ECDHE_RSA_WITH_RC4_128_SHA 

salida al intentar conectar con el servidor con el certificado autofirmado:

09-09 22:03:23.377: D/HttpsProxy(717): Https Request error 
09-09 22:03:23.377: D/HttpsProxy(717): javax.net.ssl.SSLException: Connection closed by peer 
09-09 22:03:23.377: D/HttpsProxy(717): at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method) 
09-09 22:03:23.377: D/HttpsProxy(717): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:395) 
09-09 22:03:23.377: D/HttpsProxy(717): at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:210) 
09-09 22:03:23.377: D/HttpsProxy(717): at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478) 
09-09 22:03:23.377: D/HttpsProxy(717): at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:442) 
09-09 22:03:23.377: D/HttpsProxy(717): at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:289) 
09-09 22:03:23.377: D/HttpsProxy(717): at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:239) 
09-09 22:03:23.377: D/HttpsProxy(717): at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:80) 
09-09 22:03:23.377: D/HttpsProxy(717): at libcore.net.http.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:165) 
09-09 22:03:23.377: D/HttpsProxy(717): at com.example.myfirstapp.HttpsUrlConnectionActivity$3.doInBackground(HttpsUrlConnectionActivity.java:257) 
09-09 22:03:23.377: D/HttpsProxy(717): at com.example.myfirstapp.HttpsUrlConnectionActivity$3.doInBackground(HttpsUrlConnectionActivity.java:1) 
09-09 22:03:23.377: D/HttpsProxy(717): at android.os.AsyncTask$2.call(AsyncTask.java:287) 
09-09 22:03:23.377: D/HttpsProxy(717): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 
09-09 22:03:23.377: D/HttpsProxy(717): at java.util.concurrent.FutureTask.run(FutureTask.java:137) 
09-09 22:03:23.377: D/HttpsProxy(717): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230) 
09-09 22:03:23.377: D/HttpsProxy(717): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 
09-09 22:03:23.377: D/HttpsProxy(717): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 
09-09 22:03:23.377: D/HttpsProxy(717): at java.lang.Thread.run(Thread.java:856) 

Gracias de nuevo !!

+0

Olvidé mencionar que no veo ninguna actividad del servidor cuando intento conectarme con el emulador de Android, solo con mi cliente OpenSSL. – aspergillusOryzae

+0

muy difícil de formatear esta pregunta ;-) –

+0

Disculpa, ¿hay alguna manera de que pueda hacerlo más fácil de entender antes de votar la pregunta? Estaba intentando explicar los métodos que había tomado de otras publicaciones antes de que me redirigieran a ellos. – aspergillusOryzae

Respuesta

6

Resolví mi problema - Necesitaba usar un certificado con 10.0.2.2 como el nombre común (CN) por lo que coincidía con la dirección IP localhost de Android de 10.0.2.2 en lugar de 'localhost' o '127.0.0.1'.

Editar: probablemente pueda crear un certificado con localhost como CN y '127.0.0.1' y '10 .0.2.2 'como Nombres alternativos del sujeto (SAN).

Una vez que creé 10.0.2.2 archivos cert y pem de clave privada, yo era capaz de golpear a mi servidor que ejecuta con el siguiente comando:

openssl s_server -accept 8888 -cert 10.0.2.2-cert.pem -key 10.0.2.2-key.pem -state -www 

Si desea forzar al cliente a proporcionar un certificado (aunque no se marcará), agregue el indicador -Verify 1 al comando de arriba.

Para probar el servidor en la línea de comandos que puede utilizar el siguiente (nota OpenSSL es capaz de conectarse a través de 127.0.0.1):

openssl s_client -connect 127.0.0.1:8888 

Y para añadir un certificado de cliente si el servidor lo requiere, añadir las banderas -cert client-cert.pem -key client-key.pem

en mi cliente de Android que utilizan el código siguiente para conectar (comprobación de errores eliminado):

// use local trust store (CA) 
TrustManagerFactory tmf; 
KeyStore trustedStore = null; 
InputStream in = context.getResources().openRawResource(R.raw.mycatruststore); // BKS in res/raw 
trustedStore = KeyStore.getInstance("BKS"); 
trustedStore.load(in, "insertBksPasswordHere".toCharArray()); 
tmf = TrustManagerFactory.getInstance("X509"); 
tmf.init(trustedStore); 

// load client certificate 
KeyStore clientKeyStore = loadClientKeyStore(getApplicationContext()); 
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509"); 
kmf.init(clientKeyStore, "insertPasswordHere".toCharArray()); 

SSLContext context = SSLContext.getInstance("TLS"); 

// provide client cert - if server requires client cert this will pass 
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.STRICT_HOSTNAME_VERIFIER; 

// connect to url 
URL u = new URL("https://10.0.2.2:8888/"); 
HttpsURLConnection urlConnection = (HttpsURLConnection) u.openConnection(); 
urlConnection.setSSLSocketFactory(context.getSocketFactory()); 
urlConnection.setHostnameVerifier(hostnameVerifier); 
urlConnection.connect(); 
System.out.println("Response Code: " + urlConnection.getResponseCode()); 

Usted debe obtener un código de respuesta de 2 00, y puede diseccionar la respuesta desde allí.

Aquí está el código para cargar las credenciales del cliente, que es idéntica a cargar el almacén de claves del servidor, pero con un nombre diferente de recursos y la contraseña:

private KeyStore loadClientKeyStore(Context context) { 
    InputStream in = context.getResources().openRawResource(R.yourKeyStoreFile); 
    KeyStore trusted = null; 
    trusted = KeyStore.getInstance("BKS"); 
    trusted.load(in, "yourClientPassword".toCharArray()); 
    in.close(); 
    return trusted; 
} 
2

haber perdido mi 6 - 7 horas fijas este problema y, finalmente, funcionó con

public void URLConnection(String webUrl) throws IOException, NoSuchAlgorithmException, KeyManagementException { 
     //TLSSocketFactory objTlsSocketFactory = new TLSSocketFactory(); 
     URL url = new URL(webUrl); 
     HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection(); 
     urlConnection.setRequestMethod("GET"); 
     //urlConnection.setSSLSocketFactory(objTlsSocketFactory); 

     int responseCode = urlConnection.getResponseCode(); 
     System.out.println("\nSending 'GET' request to URL : " + url); 
     System.out.println("Response Code : " + responseCode); 

     BufferedReader in = new BufferedReader(
       new InputStreamReader(urlConnection.getInputStream())); 
     String inputLine; 
     StringBuffer response = new StringBuffer(); 

     while ((inputLine = in.readLine()) != null) { 
      response.append(inputLine); 
     } 
     in.close(); 

     //print result 
     System.out.println(response.toString()); 
    } 

Y funcionó !!!!!!

Cuestiones relacionadas