我正在编写一个TCPClient
类用于与Swift中的SSL / TLS TCP套接字服务器通信,并且当服务器找不到或无法成功使用时,它会自动生成自签名证书有效的证书。这些自签名证书正用作套接字服务器
我正在尝试设置一个iOS应用,以便在TCP客户端获取无效的SSL证书时,提示用户使用类似的对话框浏览无效签名的网页。
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)
答案 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()