2012-09-10 20 views
8

Ho problemi con il collegamento di Android a un semplice server OpenSSL utilizzando l'oggetto HttpsUrlConnection (ho passato a StackOverflow e a un mucchio di tutorial online, e ho seguito gli esempi di linea per riga e non riesco ancora a capire perché il mio è rotto quando uso il mio truststore locale).HttpsUrlConnection Android javax.net.ssl.SSLException Connessione chiusa dall'errore di handshake peer quando si utilizza il truststore locale

Al momento ho un'attività Android che tenta di connettersi a un semplice OpenSSL server (posso collegare al mio server utilizzando un client OpenSSL), una volta che il HttpsUrlConnection.connect() è chiamato ricevo un mio server campione "javax.net.ssl.SSLException: Connection closed by peer" error during the SSL handshake. Forse sto installando in modo non corretto ?

Cose da notare:

  • nessuna autorizzazione cliente al momento
  • sono in grado di connettersi a https://www.google.com durante il caricamento di attendibilità predefinita
  • non sono in grado di connettersi al server su localhost con certificato auto-firmato
  • non vogliono fidarsi di tutti i certificati
  • non vogliono utilizzare Apache HttpClient
  • desidera utilizzare truststore locale solo
  • creato locale trustStore con castello gonfiabile
  • sono in grado di caricare correttamente truststore in
  • dietro un firewall proxy, proxy è impostato sul mio dispositivo virtuale Android
  • AVD impostato Android 4.1 API 16.

Le cose che ho già provato:

  • collegamento sia 127.0.0.1 and 10.0.2.2
  • utilizzando una nuova SecureRandom() with the SSLContext.init()
  • creare l'URL con 'URL u = new URL("https", "10.0.2.2", 443, "/");'
  • utilizzando TrustManagerFactory.getDefaultAlgorithms() al posto del "X509"
    • restituisce invece "Unexpected response code error 503" di "Connessione chiusa dal peer"

Grazie in anticipo per prendere il tempo di rivedere la mia domanda!

server di semplice iniziato con il comando:

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

connessione client testato con il comando:

$ openssl s_client -connect 127.0.0.1:443 

codice attività Android (a cura di rimuovere il codice in esecuzione completa di semplificazione - fatemelo sapere se più codice è necessario) - l'output dell'errore è sotto il codice.

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; 
    } 

uscita quando si collega correttamente per 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 

uscita quando si cerca di connettersi al mio server con certificato self-signed: nuovo

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) 

Grazie !!

+0

Ho dimenticato di dire che non vedo alcuna attività del server quando provo a connettermi con l'emulatore Android, solo con il mio client OpenSSL. – aspergillusOryzae

+0

molto difficile da formattare questa domanda ;-) –

+0

Scusa, c'è un modo per renderlo più facile da capire prima di votare la domanda? Stavo cercando di spiegare i metodi che avevo preso da altri post prima di essere reindirizzato a loro. – aspergillusOryzae

risposta

6

Ho risolto il problema: avevo bisogno di utilizzare un certificato con 10.0.2.2 come nome comune (CN) in modo che corrispondesse all'indirizzo IP localhost di Android 10.0.2.2 anziché "localhost" o "127.0.0.1".

Modifica: è possibile creare un certificato con localhost come CN e '127.0.0.1' e '10 .0.2.2 'come Subject Alternative Names (SAN).

Una volta ho creato 10.0.2.2 cert e file PEM chiave privata, sono stato in grado di colpire il mio server che esegue con il seguente comando:

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

Se si vuole forzare il cliente a fornire un certificato (anche se non verrà controllato), aggiungi la bandiera -Verify 1 al comando precedente.

Per testare il server dalla riga di comando è possibile utilizzare il seguente (nota OpenSSL è in grado di connettersi via 127.0.0.1):

openssl s_client -connect 127.0.0.1:8888 

E per aggiungere un cert client se il server lo richiede, aggiungere le bandiere -cert client-cert.pem -key client-key.pem

nel mio client Android ho usato il seguente codice per la connessione (error checking rimosso):

// 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()); 

Si dovrebbe ottenere un codice di risposta di 2 00, e può sezionare la risposta da lì.

Ecco il codice per caricare le credenziali del client, che è identico al caricamento di chiavi server, ma con un diverso nome di file di risorse e la password:

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

Ho sprecato i miei 6 - 7 ore risolto questo problema e, infine, ha funzionato 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()); 
    } 

E ha funzionato !!!!!!

Problemi correlati