Reputation: 3196
I am using Apple's CFNetworking to get a TLS stream. I'm having a bit of trouble porting over the Objective-C code to Swift.
With the exact same steps, it works when using Objective-C, but the handshake consistently fails when attempting with Swift.
Working Obj-c
- (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];
}
Non-working Swift
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()
}
Both are attempting to connect to the same server and same port.
Screen grabs of wireshark:
Working Obj-C
Non-working Swift
I'm pretty clueless as to what is going on. I have no idea why the Obj-C version starts a Client Hello with TLS v1.2, but Swift tries with TLS v1.0, then just gives up. No idea why the Swift version takes so long to send the Client Hello, a Keepalive packet is sent prior? Any help would be greatly appreciated.
Upvotes: 2
Views: 395
Reputation: 3196
Turns out there was no difference, I was just an idiot. I was immediately calling outputStream.write()
once the NSStreamEvent.OpenCompleted
event had be called for both input and output streams. Which was writing into the buffer of the SSL Handshake, and messing it all up.
Not found until I created a MVP for both Obj-c and Swift, which just goes to show that if you take the time to create a valid MVP, you'll probably figure it out while writing it. Now, if I can only find a way to be notified once the handshake is completed, this problem will always be avoided.
Upvotes: 2