How to configure CFStream (or NSStream) for SSL handshake?
Asked Answered
A

1

6

I'm using CFStream/NSStream to make http connections. I want to be able to detect that a SSL handshake fails for three cases:

  • case A: server is not trusted
  • case B: server is trusted but asks a client certificate
  • case C: server is not trusted and it asks a client certificate

Today without doing anithing on the SSL Properties of my CFStream, I get:

  • case A: error -9807
  • case B: no error but server refuses the connection (error 500)
  • case C: error 9807

Is there a way to configure CFStream to correctly distinguish these 3 cases ? Or to have some callbacks during SSL handshake ?

Thanks for your help.

Ackack answered 23/11, 2012 at 18:16 Comment(0)
L
4

Some time ago I ran in a same thing with CFSockets using SSL. CFStream handles all the handshake stuff. I wrote a little class addition for NSStream (Base code comes from Apple, don't have the link anymore, if I find it I'll add it). That's what worked for me.

Interface

@interface NSStream (FSNetworkAdditions)

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

@end

And Implementation

#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

That's it now you can connect to a Server like this:

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

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

Where "self" conforms to the NSStreamDelegate Protocol.

I hope these snippets helps.

Liquorice answered 14/3, 2013 at 19:58 Comment(1)
Here's the link to the Apple docs to which Arndt refers: developer.apple.com/library/ios/qa/qa1652/_index.htmlDesiderative

© 2022 - 2024 — McMap. All rights reserved.