iOS: NSInputStream / NSOutputStream - сбой SSLHandshake в CFNetwork (-9806)

Я пытаюсь открыть поток ввода-вывода на защищенном сервере, но получаю сбой CFNetwork SSLHandshake (-9806)

Я установил значения plist для доменов исключений и т. Д.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>someserver.com</key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSThirdPartyExceptionMinimumTLSVersion</key>
            <string>TLSv1.0</string>
            <key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
            <false/>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

Я также попробовал это в plist:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Вот мой код:

-(void)startStream{


NSString *urlStr = @"https://stream.someserver.com";
NSURL *website = [NSURL URLWithString:urlStr];


CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)CFBridgingRetain([website host]), 443, &readStream, &writeStream);

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


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

[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];


NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithCapacity:1];
[settings setObject:(NSString *)NSStreamSocketSecurityLevelTLSv1 forKey:(NSString *)kCFStreamSSLLevel];
[settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLValidatesCertificateChain];
[settings setObject:@"stream.someserver.com" forKey:(NSString *)kCFStreamSSLPeerName];

CFWriteStreamSetProperty((CFWriteStreamRef)outputStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);
CFReadStreamSetProperty((CFReadStreamRef)inputStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);


[inputStream open];
[outputStream open];

}

После открытия потока задержка составляет около 5 секунд, после чего выдается ошибка CFHetwork SSLHandshake (-9806).

ПРИМЕЧАНИЕ: защищенный сервер не мой, и я не могу изменить какие-либо настройки там. Это проверенный и зарекомендовавший себя сервер со многими пользователями потоковой передачи

3 ответа

Глядя на документацию Apple, кажется, что вы используете неправильные ключи.

Например

  • NSThirdPartyExceptionMinimumTLSVersion должно быть NSExceptionMinimumTLSVersion
  • NSTemporaryExceptionAllowsInsecureHTTPLoads должно быть NSExceptionAllowsInsecureHTTPLoads
  • и ECC...

Я не уверен, на каком этапе происходит сбой при установлении соединения ssl, но вы можете попробовать изменить словарь настроек на что-то вроде этого:

 NSDictionary *settings = [[NSDictionary alloc] initWithObjectsAndKeys:
                          [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates,
                          [NSNumber numberWithBool:YES], kCFStreamSSLAllowsAnyRoot,
                          [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredRoots,
                          [NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain,
                          //kCFNull,kCFStreamSSLPeerName,
                          kCFStreamSocketSecurityLevelSSLv3, kCFStreamSSLLevel,
                          [NSNumber numberWithBool:YES], kCFStreamPropertyShouldCloseNativeSocket,
                          nil];

И затем, если все прошло успешно, удалите все "нарушения безопасности", определенные выше.

В настройках SSL установите kCFStreamSSLValidatesCertificateChain в @NO полностью отключить оценку доверия сервера.

В вашей реализации делегата, когда вы впервые получаете NSStreamEventHasSpaceAvailable или же NSStreamEventHasBytesAvailable статус, а затем получить kCFStreamPropertySSLPeerTrust собственность из потока.

Вы должны получить обратно SecTrustRef, который вы можете оценить и получить информацию о:

SecTrustRef trust = (SecTrustRef)[stream propertyForKey:kCFStreamPropertySSLPeerTrust];
SecTrustResultType trustResult;
OSStatus status = SecTrustEvaluate(trust, &trustResult);
if (status != errSecSuccess) {
    NSLog(@"failed to evaluate");
} else {
    OSStatus trustResultCode = SecTrustGetTrustResult(trust, &trustResult);
}

Финал trustResultCode должен дать вам конкретную причину, почему оценка доверия не удалось. В зависимости от конкретной причины, вы можете изменить SecTrustRef или создайте совершенно новый, чтобы получить успешную оценку.

Оценка доверия сервера Apple Tech Note HTTPS действительно информативна.

Другие вопросы по тегам