【问题标题】:How to convert NSStream (NSInputStream / NSOutputStream) to SSL after stream opened?流打开后如何将 NSStream (NSInputStream / NSOutputStream) 转换为 SSL?
【发布时间】:2016-12-28 07:06:57
【问题描述】:

我有来自这段代码的 NSInputStream 和 NSOutputStream

    var readStream: Unmanaged<CFReadStream>?
    var writeStream: Unmanaged<CFWriteStream>?

    CFStreamCreatePairWithSocket(kCFAllocatorDefault, sslSocket!, &readStream, &writeStream)
    if readStream != nil && writeStream != nil {
        CFReadStreamSetProperty(readStream!.takeUnretainedValue(), kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue)
        CFWriteStreamSetProperty(writeStream!.takeUnretainedValue(), kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue)

        inputStream = readStream!.takeRetainedValue()
        outputStream = writeStream!.takeRetainedValue()

        // Create strong delegate reference to stop ARC deallocating the object
        inputDelegate = self
        outputDelegate = self

        // Now that we have a strong reference, assign the object to the stream delegates
        inputStream!.delegate = inputDelegate
        outputStream!.delegate = outputDelegate


        // Schedule our run loops. This is needed so that we can recieve NSStreamEvents
        inputStream!.scheduleInRunLoop(NSRunLoop.mainRunLoop(), forMode: NSDefaultRunLoopMode)
        outputStream!.scheduleInRunLoop(NSRunLoop.mainRunLoop(), forMode: NSDefaultRunLoopMode)

        inputStream!.open()
        outputStream!.open()
    }

问题:打开这些流后如何将其转换为 SSL?

试过关注,但我得到了NSOSStatusErrorDomain

操作无法完成。 (OSStatus 错误 -9801)

if (sslEnable) {
    let sslSettings = [
        NSString(format: kCFStreamSSLValidatesCertificateChain): kCFBooleanFalse,
        NSString(format: kCFStreamSSLPeerName): kCFNull,
        NSString(format: kCFStreamSSLIsServer): kCFBooleanTrue,
    ]
    CFReadStreamSetProperty(inputStream, kCFStreamPropertySSLSettings, sslSettings)
    CFWriteStreamSetProperty(outputStream, kCFStreamPropertySSLSettings, sslSettings)

}

【问题讨论】:

    标签: ios swift ssl nsstream nsinputstream


    【解决方案1】:

    设置套接字流

    如您所知,NSStream 确实支持在 iOS 上本地连接到远程主机;您使用CFStreamCreatePairWithSocketToHost 创建CFStream 的实例,然后桥接到NSStream。代码是正确的。

    此外,您不会在打开流后将其转换ssl;您先设置它的属性并配置连接,然后再打开它。

    对于 SSL 安全,NSStream 定义了各种安全级别的属性 [...]

    您必须在打开流之前设置属性。一旦打开,它会通过一个握手协议来找出连接的另一端使用的 SSL 安全级别。

    保护和配置连接

    在打开流对象之前,您可能需要设置与远程主机 (Stream Programming Guide) 的连接的安全性和其他功能。

    if let inputStream = inputStream, let outputStream = outputStream {
        inputStream.schedule(in: RunLoop.main, forMode: RunLoopMode.defaultRunLoopMode)
        outputStream.schedule(in: RunLoop.main, forMode: RunLoopMode.defaultRunLoopMode)
    
        if (sslEnable) {
            inputStream.setProperty(StreamSocketSecurityLevel.tlSv1,
                                   forKey: Stream.PropertyKey.socketSecurityLevelKey)
            outputStream.setProperty(StreamSocketSecurityLevel.tlSv1,
                                     forKey: Stream.PropertyKey.socketSecurityLevelKey)
    
            let sslSettings = [
                NSString(format: kCFStreamSSLValidatesCertificateChain): kCFBooleanFalse,
                NSString(format: kCFStreamSSLPeerName): kCFNull,
                NSString(format: kCFStreamSSLIsServer): kCFBooleanTrue,
                ] as [NSString : Any]
    
            inputStream.setProperty(sslSettings,
                                    forKey: Stream.PropertyKey(rawValue:
                                        kCFStreamPropertySSLSettings as String))
            outputStream.setProperty(sslSettings,
                                     forKey: Stream.PropertyKey(rawValue:
                                        kCFStreamPropertySSLSettings as String))
    
        }
        inputStream.open()
        outputStream.open()
    }
    

    【讨论】:

    • 您好,感谢您的回复。但我的程序将作为服务器工作。所以使用 CFStreamCreatePairWithSocketToHost 将不适用,不是吗?导致程序将接收连接,而不是建立连接。
    • 另外我需要打开我的连接,因为我的客户端会在发送 SSL Hello Packet 之前先发送确认信息。一旦我收到这些确认。我需要更改流来处理 SSL hello 数据包。我确实尝试过inputStream.close(),然后在设置 SSL 后重新打开它。但它仍然显示相同的错误“无法完成操作。(OSStatus 错误 -9801)”。所以你认为我们不能这样做吗?我是否应该给客户端一个新端口,以便客户端可以连接到新的流,我将在打开它之前设置 SSL 设置。
    • 我明白了。 iOS 文档对此持坚决态度:NSStream 一旦打开就无法更改。我解释这一点的一种方式是,流是套接字层将通过它进行通信的通道;有点像打开的文件。建立连接后,您是否考虑过将流量重定向到新套接字?
    【解决方案2】:

    这是errSSLNegotiationSecureTransport.hSecurity 框架中的错误

    -9801 The cipher suite negotiation failed.

    您尝试连接的服务器可能具有非常旧的 SSL 实现,或者您的服务器密码套件配置与手机的配置不匹配。

    Source

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多