2012-09-10 1 views
8

HttpsUrlConnection 개체를 사용하여 간단한 OpenSSL 서버에 안드로이드를 연결하는 데 문제가 있습니다 (StackOverflow 및 온라인 자습서의 낱단 및 선을위한보기를위한보기를 거의 따르고 나는 나의 현지 신망을 사용할 때 나의 것이 왜 끊기는 지 아직도 이해할 수 없다).Android HttpsUrlConnection javax.net.ssl.SSLException 로컬 트러스트 스토어를 사용할 때 피어 핸드 셰이크 오류로 연결이 닫힘

나는 현재에 연결을 시도 안드로이드 활동을

간단한 OpenSSL serverHttpsUrlConnection.connect()가 호출되면 내가 잘못 "javax.net.ssl.SSLException: Connection closed by peer" error during the SSL handshake.은 아마도 내가 설정하고 내 샘플 서버를 수신 (I는 OpenSSL을 클라이언트를 사용하여 내 서버에 연결할 수 있습니다) ?

유의할 것들 :

  • 순간 기본 신뢰 저장소
  • 를로드 할 때 https://www.google.com에 연결할 수
  • 오전없는 클라이언트 인증
  • 모든 인증서를 신뢰하지 않으려는 자체 서명 된 인증서를 사용하여 로컬 호스트에서 서버에 연결할 수 없습니다입니다
  • 현지 만들어 지역의 신뢰 저장소를 사용하려면 아파치 HttpClient를 사용하지 않으려는 탄력이 성 올바르게 프록시 방화벽
  • 에 신뢰를로드 할 수
  • 오전과 신뢰, 프록시는
  • AVD가로 설정 내 안드로이드 가상 장치에 설정되어.

것들 난 이미 시도 :

  • 'URL u = new URL("https", "10.0.2.2", 443, "/");'
  • TrustManagerFactory.getDefaultAlgorithms()를 사용하는 대신에 "X509"
      과 URL을 생성하는 새로운 SecureRandom() with the SSLContext.init()
    • 를 사용하여 두 127.0.0.1 and 10.0.2.2
    • 에 연결
    • 대신 "Unexpected response code error 503"이 표시됩니다. 의
  • "연결이 피어에 의해 폐쇄"

내 질문을 검토 할 수있는 시간을내어 사전에 감사합니다! 명령 테스트

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

클라이언트 연결 :

간단한 서버가 명령으로 시작

$ openssl s_client -connect 127.0.0.1:443 

안드로이드 활동 코드 (단순화를 위해 완전한 실행 코드를 제거 편집 - 좀 더 코드 경우 알려 주시기 바랍니다 오류 출력은 코드 아래에 있습니다.https://www.google.com에 제대로 연결

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

출력 :

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 

출력 자체 서명 인증서를 사용하여 내 서버에 연결을 시도 : 다시

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) 

감사합니다!

+0

내 안드로이드 에뮬레이터와 연결하려고 할 때 내 OpenSSL 클라이언트에만 서버 활동이 표시되지 않는다는 사실을 잊어 버렸습니다. – aspergillusOryzae

+0

이 질문의 형식을 지정하기가 매우 어려움 ;-) –

+0

죄송합니다. 질문을 투표하기 전에 이해하기 쉽도록 방법이 있습니까? 나는 그들에게 재 지시되기 전에 다른 게시물에서 취한 방법을 설명하려고 노력했다. – aspergillusOryzae

답변

6

내 문제가 해결되었습니다. 공용 호스트 이름 (CN)으로 10.0.2.2의 인증서를 사용하여 'localhost'또는 '127.0.0.1'대신 10.0.2.2의 Android localhost IP 주소와 일치해야했습니다.

편집 : localhost를 CN으로, '127.0.0.1'및 '10 .0.2.2 '를 주체 대체 이름 (SAN)으로 만들 수 있습니다. 내가 10.0.2.2 인증서 및 개인 키 PEM 파일을 생성하면

, 내 서버에서 다음 명령을 실행 칠 수 있었다 : 당신이 비록 (인증서를 제공하기 위해 클라이언트를 강제하려면

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

확인되지 않음) 위의 명령에 플래그 -Verify 1을 추가하십시오.

다음 사용할 수있는 명령 줄에서 서버를 테스트하기 위해 (주하려면 openssl은 127.0.0.1를 통해 연결할 수) :

openssl s_client -connect 127.0.0.1:8888 

를 그리고 서버가 필요한 경우 클라이언트 인증서를 추가하려면 추가

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

당신은 2의 응답 코드를 얻어야한다 : 내 안드로이드 클라이언트에서 플래그 -cert client-cert.pem -key client-key.pem

나는 (오류가 제거 확인)를 연결하려면 다음 코드를 사용 00, 거기에서 응답을 분석 할 수 있습니다. 7시간 마지막으로이 문제를 해결하고 - 제 6

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

내가 낭비 : 여기

서버 키 저장소를로드에 있지만 다른 자원 파일 이름 및 암호와 동일 클라이언트 자격 증명을로드하는 코드이다 그것과 함께 작동

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

그리고 그것은 일했다 !!!!!!