Swift NSStream()SSL - 要求用户确认

时间:2015-09-14 01:17:04

标签: ios sockets ssl nsstream

我正在编写一个TCPClient类用于与Swift中的SSL / TLS TCP套接字服务器通信,并且当服务器找不到或无法成功使用时,它会自动生成自签名证书有效的证书。这些自签名证书正用作套接字服务器

我正在尝试设置一个iOS应用,以便在TCP客户端获取无效的SSL证书时,提示用户使用类似的对话框浏览无效签名的网页。

这是我想向用户显示的对话框:

Verify Server Identity

以下是TCP连接的方式:

public class TCPClient: NSObject, NSStreamDelegate {
    let serverAddress = "127.0.0.1"
    let serverPort = 7000

    private var inputStream: NSInputStream?
    private var outputStream: NSOutputStream?

    public func connect() {
        println("connecting...")

        NSStream.getStreamsToHostWithName(self.serverAddress, port: self.serverPort, inputStream: &self.inputStream, outputStream: &self.outputStream)

        self.inputStream!.delegate = self
        self.outputStream!.delegate = self

        self.inputStream!.open()
        self.outputStream!.open()

        self.inputStream!.setProperty(NSStreamSocketSecurityLevelTLSv1, forKey: NSStreamSocketSecurityLevelKey)
        self.outputStream!.setProperty(NSStreamSocketSecurityLevelTLSv1, forKey: NSStreamSocketSecurityLevelKey)

        var buffer: [UInt8] = [0]
        // buffer is a UInt8 array containing bytes of a string.
        self.outputStream!.write(&buffer, maxLength: buffer.count)
    }

    public func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
        println("stream event.")
    }
}

目前我只在尝试连接时看到这个:

connecting...
2015-09-13 19:48:25.562 AppName[] CFNetwork SSLHandshake failed (-9807)

2 个答案:

答案 0 :(得分:1)

首先,确保您熟悉iOS 9和OS X 10.11中的新app transport security主题,并根据需要应用。如果可能,最好在服务器中支持适当的技术。

在连接流之前,请使用NSURLSession为您的服务器创建模拟任务。实现- URLSession:didReceiveChallenge:completionHandler:委托方法,并验证那里的服务器证书。如果不受信任,则向用户显示警报。我不熟悉系统提供的显示证书信息的方法,因此您可能需要实现它。用户批准后,将挑战中的证书添加到您应用的钥匙串中。这将允许流连接到服务器。挑战结束后,像往常一样尝试进行流连接,然后继续正常的应用工作流程。

答案 1 :(得分:0)

设置绑定失败,因为在打开连接后根据documentation更改了属性:

  

您必须在打开流之前设置属性。一旦打开,它将通过握手协议找出连接另一端正在使用的SSL安全级别。如果安全级别与指定的属性不兼容,则流对象将生成错误事件。

此外,NSStream类不支持连接到iOS上的远程主机。解释流编程指南,使用CFStream建立套接字连接,然后将CFStreams强制转换为NSStreams

在Swift 3中解决你的代码片段,它变为:

inputStream.schedule(in: RunLoop.main, forMode: RunLoopMode.defaultRunLoopMode)
outputStream.schedule(in: RunLoop.main, forMode: RunLoopMode.defaultRunLoopMode)

inputStream.setProperty(StreamSocketSecurityLevel.tlSv1,
                        forKey: Stream.PropertyKey.socketSecurityLevelKey)
outputStream.setProperty(StreamSocketSecurityLevel.tlSv1,
                         forKey: Stream.PropertyKey.socketSecurityLevelKey)

inputStream.open()
outputStream.open()