2013-10-03 4 views
1

나는 자바에서 SSLServerSocket에 클래스 다음의 목표 C의 스트림 클래스 (CF와 NS 모두)를 사용하여 보안 소켓 연결을 설정하고 연결 (-9824) 실패했습니다.SSL 소켓 연결 : CFNetwork에서 SSLHandshake 자바 SSLServerSocket에

자바 SSLServerSocket에 코드 (각 연결 SecureClientWorker 거래) :

public void listenSocket(int port){ 
     try { 
      System.setProperty("javax.net.ssl.keyStore", "path/to/certificate(signed_by_own_root_certificate).jks"); 
//I try to make this root certificate trusted by iOS (see obj-c code below) 
      System.setProperty("javax.net.ssl.keyStorePassword", "PASSWORD..."); 
     } catch (IOException e1) { 
      e1.printStackTrace(); 
     } 
     try{ 
      SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); 
      server = (SSLServerSocket) ssf.createServerSocket(port); 

      logger.info("Started to listen on port: "+port); 
     }catch(Exception e){ 
      logger.warning("Could not listen on port: "+port); 
      e.printStackTrace(); 
     } 

     while(running){ 
      SecureClientWorker w; 
      try{ 
       w = new SecureClientWorker(server.accept(), this); 
       Thread t = new Thread(w); 
       t.start(); 
      }catch(IOException e){ 
       if(running) 
        e.printStackTrace(); 
      } 
     } 

    } 

목표 C 클라이언트 코드 :

[self addRootCert]; //This is where I attempt to make the root certificate trusted, If needed I can post it 
CFReadStreamRef readStream; 
CFWriteStreamRef writeStream; 
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)self.ip.text, self.portNumber.text.intValue, &readStream, &writeStream); 

// Set options then bridge to ARC: 
NSDictionary *settings = [[NSDictionary alloc] initWithObjectsAndKeys: 
          (id)kCFStreamSocketSecurityLevelNegotiatedSSL, kCFStreamPropertySocketSecurityLevel, 
          [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates, 
          [NSNumber numberWithBool:YES], kCFStreamSSLAllowsAnyRoot, 
          [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredRoots, 
          [NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain, 
          nil]; 

if (readStream) { 
    CFReadStreamSetProperty(readStream, kCFStreamPropertySSLSettings, (__bridge CFDictionaryRef)settings); 
    inStream = (__bridge_transfer NSInputStream*) readStream; 
    [inStream setDelegate:self]; 
    [inStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
    [inStream open]; 
} 

if (writeStream) { 
    CFWriteStreamSetProperty(writeStream, kCFStreamPropertySSLSettings, (__bridge CFDictionaryRef)settings); 
    outStream = (__bridge_transfer NSOutputStream*) writeStream; 
    [outStream setDelegate:self]; 
    [outStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
    [outStream open]; 
} 

그러나이 결과 나는 다음 코드를 사용하여 이렇게 설정해야 오류 코드 CFNetwork SSLHandshake failed (-9824)와 하천 객체는 NSStreamDelegate 방법에 오류 NSStreamEventErrorOccurred를 반환합니다. 자바 측면에서

, IOException은 다음과 던져 나타납니다 :

in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); //ClientSocket is just the connection to the client 
[...] 
in.readLine(); 

의 printStackTrace는 말한다 : javax.net.ssl.SSLHandshakeException: no cipher suites in common

내가 만들 필요가 수행합니다 KeyManager (나는 다른 곳에서 읽을 때)? SSLServerSocket을 열어 놓은 것에서부터 아무 것도하지 말고 어떻게해야합니까?

도움이 될 것입니다. 이 시스템 속성을 설정하지 못할 수 있기 때문에

편집

I는 서버 코드를 변경했습니다.

나의 새로운 코드는 다음과 같습니다 나는 TrustManager 내 자신을 만들려고 몇 가지 조사 후 java.security.KeyManagementException: Default SSLContext is initialized automatically

하지만 여전히

를 작동시킬 수 없습니다 : 지금이 오류 메시지가 그러나

KeyStore ks = KeyStore.getInstance("JKS"); 
      FileInputStream ksIs = new FileInputStream(new File("path/to/certificate(signed_by_own_root_certificate).jks")); 
      try { 
       ks.load(ksIs, "PASSWORD...".toCharArray()); 
      } catch (NoSuchAlgorithmException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } catch (CertificateException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } finally { 
       if (ksIs != null) { 
        ksIs.close(); 
       } 
      } 

      KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 
      kmf.init(ks, "PASWD".toCharArray()); 
      KeyManager keyManagers[] = kmf.getKeyManagers(); 
      SSLContext sc = SSLContext.getDefault(); 
      sc.init(keyManagers, null, new SecureRandom()); 
      SSLServerSocketFactory socketFactory = sc.getServerSocketFactory(); 

      server = (SSLServerSocket) socketFactory.createServerSocket(port); 

나는 무엇을 놓치고?

답변

4

응용 프로그램에서 키 저장소 파일을 읽을 수 있고 암호가 맞다고 가정하면이 소켓 팩토리를 가져 오기 전에 Java 응용 프로그램에서 SSL/TLS 연결을 사용했다고 추측 할 수 있습니다. 다른 라이브러리에 의해 암묵적으로 수행됨).

javax.net.ssl.keyStore* 시스템 속성은 기본 SSLContext을 초기화 한 번 사용된다. 해당 컨텍스트가 초기화 된 후에 변경하면 아무 것도 수행되지 않습니다.

javax.net.ssl.SSLHandshakeException: no cipher suites in common 오류 메시지

가 발견되거나 제대로로드되지 않는 키 스토어의 아주 전형적이다. 이것은 인증서/키 자료없이 RSA/DSA 암호 스위트를 사용할 수 없다는 사실에서 비롯됩니다. 원격 클라이언트가 찾고자하는 암호 스위트입니다.

명령 줄에서 이러한 속성을 설정하거나 응용 프로그램의 맨 처음에 그들을 설정하는 것이 확인하는 빠른 방법 (및 서버 코드를 다른 곳으로 변경하지 말 것).

응용 프로그램에서 이러한 설정이 전역이 아니게하려면 KeyManager을 실제로 초기화해야합니다. 기본 SSLContext을 다시 구성하려는 때문에 편집에 따라


, java.security.KeyManagementException: Default SSLContext is initialized automatically 발생합니다. 대신 새로운 인스턴스 사용

SSLContext sc = SSLContext.getInstance("TLS"); 
+0

을하지만 키 저장소를 열 수 없습니다라고 오류 메시지를 얻을하지 않습니다 ... 나는 또한 그냥 "업데이트 된 코드 –

+0

과 편집을 추가했습니다 *하지만 난 몰라 키 스토어를 열 수 없다는 오류 메시지가 표시됩니다. * ": 그렇지 않습니다. 속성을 설정하기 전에 기본값 인'SSLContext'가 키 스토어 (기본값)없이 초기화 되었다면 너무 늦었습니다. (새 편집은 다른 문제입니다.) – Bruno

+0

고맙습니다. 편집이 수정되었습니다! (당신이 말했던 것부터 먼 길을 따라야 만했기 때문에 코드에서 시스템 속성을 설정할 수 없었습니다!) 그리고 .getInstance() 메서드를 사용해 주셔서 감사합니다! 'TLS'는 사용하기에 가장 좋은 것입니까? –