首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SSL套接字连接: CFNetwork SSLHandshake连接到SSLServerSocket失败(-9824)

SSL套接字连接: CFNetwork SSLHandshake连接到SSLServerSocket失败(-9824)
EN

Stack Overflow用户
提问于 2013-10-03 13:36:15
回答 1查看 7.4K关注 0票数 1

我正在使用Java中的SSLServerSocket类以及目标c中的Stream类(包括CF和NS)来建立一个安全的套接字连接。

Java SSLServerSocket代码(SecureClientWorker处理每个连接):

代码语言:javascript
复制
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客户端代码:

代码语言:javascript
复制
[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对象返回NSStreamDelegate方法中的错误NSStreamEventErrorOccurred

在Java方面,IOException似乎会被抛出,如下所示:

代码语言:javascript
复制
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 )?

任何帮助都将不胜感激!

编辑

我已经更改了服务器代码,因为它可能无法设置系统属性。

我的新代码是:

代码语言:javascript
复制
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,但没能让它继续工作

我遗漏了什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-10-03 14:22:18

假设您的应用程序可以读取keystore文件,并且密码是正确的,那么我的猜测是,在获得这个套接字工厂之前,您已经在Java应用程序中使用了SSL/TLS连接(这可能是由另一个库隐式完成的)。

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。使用一个新实例来代替:

代码语言:javascript
复制
SSLContext sc = SSLContext.getInstance("TLS");
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19160684

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档