6

CFStream/NSStream を使用して http 接続を確立しています。次の 3 つのケースで SSL ハンドシェイクが失敗したことを検出できるようにしたいと考えています。

  • ケース A: サーバーが信頼されていない
  • ケース B: サーバーは信頼されているが、クライアント証明書を要求する
  • ケース C: サーバーが信頼されておらず、クライアント証明書を要求する

今日、CFStream の SSL プロパティで何もしなくても、次のようになります。

  • ケース A: エラー -9807
  • ケース B: エラーは発生しないが、サーバーが接続を拒否する (エラー 500)
  • ケース C: エラー 9807

これら 3 つのケースを正しく区別するように CFStream を構成する方法はありますか? または、SSL ハンドシェイク中にいくつかのコールバックを行うには?

ご協力いただきありがとうございます。

4

1 に答える 1

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

そして実装

#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

これで、次のようにサーバーに接続できます。

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

        inputStream.delegate  = self;
        outputStream.delegate = self;

「自己」がNSStreamDelegateプロトコルに準拠している場合。

これらのスニペットがお役に立てば幸いです。

于 2013-03-14T19:58:08.840 に答える