Разница между Apple TLS с Objective-C и Swift

Я использую Apple CFNetworking для получения потока 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:

Рабочий объект-C

Снимок рабочего экрана Wireshark

Нерабочий Свифт

Неработающий снимок экрана Wireshark

Я совершенно не понимаю, что происходит. Я понятия не имею, почему версия Obj-C запускает Client Hello с TLS v1.2, но Swift пытается использовать TLS v1.0, а затем просто сдается. Понятия не имею, почему версия Swift так долго отправляет Client Hello, пакет Keepalive отправляется раньше? Любая помощь будет принята с благодарностью.


person nathansizemore    schedule 16.05.2016    source источник
comment
Это может ничего не изменить, но порядок, в котором вы устанавливаете NSStreamSocketSecurityLevelNegotiatedSSL, и делегат меняется местами между версиями ObjC и Swift.   -  person zneak    schedule 17.05.2016
comment
Это не имеет значения. Рукопожатие не начинается до первого вызова чтения или записи на любом конце потока.   -  person nathansizemore    schedule 17.05.2016
comment
А как насчет контекста, в котором вызывается этот метод connect()? Это в основной теме?   -  person Ken Thomases    schedule 17.05.2016
comment
Да, оба в основной ветке.   -  person nathansizemore    schedule 17.05.2016


Ответы (1)


Оказалось, что разницы нет, я был просто идиотом. Я немедленно вызвал outputStream.write(), как только событие NSStreamEvent.OpenCompleted было вызвано как для входного, так и для выходного потоков. Который записывался в буфер рукопожатия SSL и все портил.

Не нашел, пока я не создал MVP для Obj-c и Swift, что просто показывает, что если вы потратите время на создание действительного MVP, вы, вероятно, поймете это во время его написания. Теперь, если я смогу найти способ получать уведомления только после завершения рукопожатия, этой проблемы всегда можно будет избежать.

person nathansizemore    schedule 17.05.2016