2013-10-03 2 views
1

Я настраиваю соединение с защищенным сокетом с использованием класса SSLServerSocket в Java, а затем классы Stream (как CF, так и NS) в объекте c. она у меня настроить так, с помощью следующего кода:Соединение с SSL-соединением: CFNetwork SSLHandshake failed (-9824), подключающийся к Java SSLServerSocket

Java 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), а объект inStream возвращает ошибку NSStreamEventErrorOccurred в методе NSStreamDelegate.

На стороне Java, 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, пожалуйста)?

Любая помощь была бы принята с благодарностью!

EDIT

Я изменил код сервера, так как он не может быть в состоянии установить свойство системы.

Мой новый код:

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

Однако теперь я получаю сообщение об ошибке: java.security.KeyManagementException: Default SSLContext is initialized automatically

После некоторых исследований я попытался сделать мои собственные TrustManager, но не мог заставить его работать еще

Что мне не хватает?

ответ

4

Предполагая, что файл хранилища ключей может быть прочитан вашим приложением и что пароль верен, я предполагаю, что вы использовали соединение SSL/TLS в своем приложении Java где-то перед тем, как получить эту фабрику сокетов (это может быть сделанное неявно другой библиотекой).

Свойства системы javax.net.ssl.keyStore* используются только один раз для инициализации по умолчанию SSLContext. Изменение их после инициализации контекста ничего не сделает.

Сообщение об ошибке javax.net.ssl.SSLHandshakeException: no cipher suites in common является типичным для хранилища ключей, которое не найдено или не загружено должным образом. Это происходит из-за того, что без какого-либо сертификата/ключевого материала ни один из наборов шифров RSA/DSA не включен: это те, которые будет искать удаленный клиент.

Быстрый способ проверить это - установить эти свойства в командной строке или установить их в самом начале приложения (и не изменять их в другом месте на вашем серверном коде).

Если вам нужно, чтобы эти настройки не были глобальными в вашем приложении, вам необходимо инициализировать KeyManager.


После правки, java.security.KeyManagementException: Default SSLContext is initialized automatically происходит потому, что вы пытаетесь перенастроить по умолчанию SSLContext. Используйте новый экземпляр вместо:

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

Но я не получаю никаких сообщений об ошибке заявив, что не может открыть хранилище ключей .. Я также только что добавил редактирования с обновленным кодом –

+0

«* Но я не получить сообщения об ошибках, говорящие, что он не может открыть хранилище ключей * ": вы бы этого не сделали. Если по умолчанию «SSLContext» был инициализирован без какого-либо хранилища ключей (по умолчанию), прежде чем вы установите свои свойства, слишком поздно. (Ваше новое редактирование - это другая проблема.) – Bruno

+0

Большое вам спасибо, исправлено исправление! (Из того, что вы сказали, что это нужно сделать долгим путем, я не смог установить системные свойства из кода!) И спасибо за метод .getInstance()! Используется ли 'TLS' лучший? –

Смежные вопросы