Я настраиваю соединение с защищенным сокетом с использованием класса 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
, но не мог заставить его работать еще
Что мне не хватает?
Но я не получаю никаких сообщений об ошибке заявив, что не может открыть хранилище ключей .. Я также только что добавил редактирования с обновленным кодом –
«* Но я не получить сообщения об ошибках, говорящие, что он не может открыть хранилище ключей * ": вы бы этого не сделали. Если по умолчанию «SSLContext» был инициализирован без какого-либо хранилища ключей (по умолчанию), прежде чем вы установите свои свойства, слишком поздно. (Ваше новое редактирование - это другая проблема.) – Bruno
Большое вам спасибо, исправлено исправление! (Из того, что вы сказали, что это нужно сделать долгим путем, я не смог установить системные свойства из кода!) И спасибо за метод .getInstance()! Используется ли 'TLS' лучший? –