如何为SSL握手配置CFStream(或NSStream)?

Moh*_*nia 6 ssl objective-c nsstream cfnetwork cfstream

我正在使用CFStream/NSStream来建立http连接.我希望能够在三种情况下检测到SSL握手失败:

  • 案例A:服务器不受信任
  • 情况B:服务器是可信的但是要求客户端证书
  • 情况C:服务器不受信任,它会询问客户端证书

今天没有对我的CFStream的SSL属性进行测试,我得到:

  • 案例A:错误-9807
  • 情况B:没有错误,但服务器拒绝连接(错误500)
  • 案例C:错误9807

有没有办法配置CFStream来正确区分这三种情况?或者在SSL握手期间进行一些回调?

谢谢你的帮助.

Arn*_*ein 4

不久前,我使用 SSL 与 CFSockets 运行了同样的事情。CFStream 处理所有握手的事情。我为 NSStream 编写了一些类添加(基本代码来自 Apple,不再有链接,如果我找到它,我会添加它)。这对我有用。

界面

@interface NSStream (FSNetworkAdditions)

+ (void)qNetworkAdditions_getStreamsToHostNamed:(NSString *)hostName
                                           port:(NSInteger)port
                                    inputStream:(out NSInputStream **)inputStreamPtr
                                   outputStream:(out NSOutputStream **)outputStreamPtr;

@end
Run Code Online (Sandbox Code Playgroud)

及实施

#import "FSNetworkAdditions.h"

@implementation NSStream (FSNetworkAdditions)

+ (void)qNetworkAdditions_getStreamsToHostNamed:(NSString *)hostName
                                           port:(NSInteger)port
                                    inputStream:(out NSInputStream **)inputStreamPtr
                                   outputStream:(out NSOutputStream **)outputStreamPtr
{
    CFReadStreamRef     readStream;
    CFWriteStreamRef    writeStream;

    assert(hostName != nil);
    assert( (port > 0) && (port < 65536) );
    assert( (inputStreamPtr != NULL) || (outputStreamPtr != NULL) );

    readStream = NULL;
    writeStream = NULL;

    CFStreamCreatePairWithSocketToHost(
                                       NULL,
                                       (CFStringRef) hostName,
                                       port,
                                       ((inputStreamPtr  != NULL) ? &readStream : NULL),
                                       ((outputStreamPtr != NULL) ? &writeStream : NULL)
                                       );

    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];

    if (readStream) {
        CFReadStreamSetProperty(readStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);
    }

    if (writeStream) {
        CFWriteStreamSetProperty(writeStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);
    }

    if (inputStreamPtr != NULL) {
        *inputStreamPtr  = CFBridgingRelease(readStream);
    }
    if (outputStreamPtr != NULL) {
        *outputStreamPtr = CFBridgingRelease(writeStream);
    }


}

@end
Run Code Online (Sandbox Code Playgroud)

现在您可以像这样连接到服务器:

NSInputStream   *inputStream;
NSOutputStream  *outputStream;
[NSStream qNetworkAdditions_getStreamsToHostNamed:host 
                                             port:port 
                                      inputStream:&inputStream 
                                     outputStream:&outputStream];

        inputStream.delegate  = self;
        outputStream.delegate = self;
Run Code Online (Sandbox Code Playgroud)

其中“self”符合 NSStreamDelegate 协议。

我希望这些片段有帮助。

  • 以下是 Arndt 引用的 Apple 文档的链接:https://developer.apple.com/library/ios/qa/qa1652/_index.html (2认同)