Apple TLS与Objective-C和Swift的区别

Apple TLS与Objective-C和Swift的区别

问题描述:

我正在使用Apple的CFNetworking获取TLS流。我在将Objective-C代码移植到Swift时遇到了一些麻烦。Apple TLS与Objective-C和Swift的区别

使用完全相同的步骤,它在使用Objective-C时起作用,但在尝试使用Swift时握手始终失败。

工作对象 -

- (void)connect() 
{ 
    CFReadStreamRef readStream; 
    CFWriteStreamRef writeStream; 
    CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, 
             (__bridge CFStringRef)hostAddress, 
             port, 
             &readStream, 
             &writeStream); 

    self.inputStream = (__bridge_transfer NSInputStream *)readStream; 
    self.outputStream = (__bridge_transfer NSOutputStream *)writeStream; 

    [self.inputStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL 
         forKey:NSStreamSocketSecurityLevelKey]; 
    [self.outputStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL 
         forKey:NSStreamSocketSecurityLevelKey]; 

    [self.inputStream setDelegate:self]; 
    [self.outputStream setDelegate:self]; 

    [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] 
           forMode:NSDefaultRunLoopMode]; 

    [self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] 
           forMode:NSDefaultRunLoopMode]; 

    [self.inputStream open]; 
    [self.outputStream open]; 
} 

非工作斯威夫特

func connect() { 
    var readStream: Unmanaged<CFReadStream>? 
    var writeStream: Unmanaged<CFWriteStream>? 

    let host = "some_host" 
    let hostAsCFString = host as NSString 
    CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, 
             hostAsCFString, 
             1337, 
             &readStream, 
             &writeStream) 

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

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

    inputStream!.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, 
          forKey: NSStreamSocketSecurityLevelKey) 
    outputStream!.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, 
           forKey: NSStreamSocketSecurityLevelKey) 

    inputStream!.scheduleInRunLoop(.currentRunLoop(), forMode: NSDefaultRunLoopMode) 
    outputStream!.scheduleInRunLoop(.currentRunLoop(), forMode: NSDefaultRunLoopMode) 

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

两者都试图连接到同一台服务器和同一端口。

的Wireshark的屏幕抓取:

工作对象 -

Working Wireshark screen grab

非工作斯威夫特

Non working Wireshark screen grab

我为正在发生的事情是很笨。我不知道为什么Obj-C版本使用TLS v1.2启动Client Hello,但Swift尝试使用TLS v1.0,然后放弃。不知道为什么Swift版本需要这么长时间才能发送客户端Hello,Keepalive数据包是先发送的?任何帮助将不胜感激。

+1

这可能不会改变任何内容,但是您设置NSStreamSocketSecurityLevelNegotiatedSSL和委托的顺序在您的ObjC和Swift版本之间交换。 – zneak

+0

这并不重要。握手直到在流的任一端上进行第一次读取或写入调用才开始。 – nathansizemore

+0

这个'connect()'方法被调用的上下文怎么样?它在主线程上吗? –

原来没有什么区别,我只是一个白痴。一旦NSStreamEvent.OpenCompleted事件被输入输出流调用,我立即调用outputStream.write()。这是写入SSL握手的缓冲区,并搞砸了。

直到我为Obj-c和Swift创建了一个MVP,它才表明如果你花时间创建一个有效的MVP,那么在编写它时可能会弄清楚它。现在,如果我只能在握手完成后找到通知的方式,则始终可以避免此问题。