kCFStreamPropertySocketSecurityLevel to kCFStreamSocketSecurityLevelNegotiatedSSL causes OSStatus errSSLXCertChainInvalid (-9807)

1,151 views
Skip to first unread message

Heath

unread,
Jan 24, 2011, 12:58:15 AM1/24/11
to cocoa-unbound
Cross-posed at stackoverflow (if this is a faux-pax, please let me
know!):
http://stackoverflow.com/questions/4755499/kcfstreampropertysocketsecuritylevel-to-kcfstreamsocketsecuritylevelnegotiatedssl

Why does setting kCFStreamPropertySocketSecurityLevel to
kCFStreamSocketSecurityLevelNegotiatedSSL below cause my SSL handshake
to fail? I expect that my handshake would always succeed because I
set kCFStreamSSLValidatesCertificateChain to kCFBooleanFalse in my
readStream's kCFStreamPropertySSLSettings.

Thanks!

- (void) connectSecurely {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL,
(CFStringRef)@"mcheath.local",
8443,
&readStream,
&writeStream);

NSDictionary *sslSettings = [NSDictionary
dictionaryWithObjectsAndKeys:
(id)kCFBooleanFalse,
(id)kCFStreamSSLValidatesCertificateChain,
nil];

CFReadStreamSetProperty(readStream,
kCFStreamPropertySSLSettings,
sslSettings);

/* Turning on this setting makes the SSL handshake fail with OSStatus
-9807 */
CFReadStreamSetProperty(readStream,
kCFStreamPropertySocketSecurityLevel,
kCFStreamSocketSecurityLevelNegotiatedSSL);

self.inputStream = (NSInputStream *)readStream;
self.outputStream = (NSOutputStream *)writeStream;
[self.inputStream setDelegate:self];
[self.outputStream setDelegate:self];

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

CFReadStreamOpen(readStream);
CFWriteStreamOpen(writeStream);
}

#pragma mark -
#pragma mark NSStreamDelegate

- (void)stream:(NSStream *)aStream
handleEvent:(NSStreamEvent)eventCode {
switch (eventCode) {
case NSStreamEventNone:
NSLog(@"NSStreamEventNone");
break;
case NSStreamEventOpenCompleted:
NSLog(@"NSStreamEventOpenCompleted");
break;
case NSStreamEventHasBytesAvailable:
NSLog(@"NSStreamEventHasBytesAvailable");
break;
case NSStreamEventHasSpaceAvailable:
NSLog(@"NSStreamEventHasSpaceAvailable");
break;
case NSStreamEventErrorOccurred:
NSLog(@"NSStreamEventErrorOccurred: %@", [aStream streamError]);
NSLog(@"SSL Settings: %@", [aStream propertyForKey:(NSString *)
kCFStreamPropertySSLSettings]);
break;
case NSStreamEventEndEncountered:
NSLog(@"NSStreamEventEndEncountered");
break;
default:
break;
}
}

Ken Thomases

unread,
Jan 24, 2011, 9:16:51 AM1/24/11
to cocoa-...@googlegroups.com
On Jan 23, 2011, at 11:58 PM, Heath wrote:

> Why does setting kCFStreamPropertySocketSecurityLevel to
> kCFStreamSocketSecurityLevelNegotiatedSSL below cause my SSL handshake
> to fail? I expect that my handshake would always succeed because I
> set kCFStreamSSLValidatesCertificateChain to kCFBooleanFalse in my
> readStream's kCFStreamPropertySSLSettings.

Try reversing the order. It's possible that setting the security level sets the SSL settings to their defaults, obliterating your disabling of certification validation. First enable SSL, then set the SSL settings.

Regards,
Ken

Heath

unread,
Jan 24, 2011, 9:34:35 AM1/24/11
to cocoa-unbound
That was it!
Do you want to answer the stackoverflow question, so you can have the
rep, or do you just want me to point to this response?

Heath

unread,
Jan 24, 2011, 9:45:50 AM1/24/11
to cocoa-unbound
I have another related issue. I have another method in the same class
that creates a CFReadStream and places the self-signed cert in the
keychain. I expect that if I replace my server's cert with a
different self-signed cert, my CFReadStream should fail with
errSSLXCertChainInvalid. This happens fine until I create a
CFReadStream with the kCFStreamPropertySSLSettings above. After that,
my keychain-verifying CFReadStream says that my server's invalid cert
is valid. I've tried explicitly re-setting
kCFStreamSSLValidatesCertificateChain to kBooleanTrue, but that has no
effect.

If you want the rep, the stackoverflow question is here:
http://stackoverflow.com/questions/4779274/setting-kcfstreamsslvalidatescertificatechain-in-one-cfreadstream-causes-other-cf

- (void) verifyWithKeychain {
self.inputStream = nil;
self.outputStream = nil;

self.verifyOnHasSpaceAvailable = NO;

OSStatus err = SecItemAdd((CFDictionaryRef) [NSDictionary
dictionaryWithObjectsAndKeys:
(id)
kSecClassCertificate, kSecClass,
self.certificate,
kSecValueRef,
nil],
NULL);
assert(err == noErr || err == errSecDuplicateItem);

CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL,
(CFStringRef)@"localhost",
8443,
&readStream,
&writeStream);

CFReadStreamSetProperty(readStream,
kCFStreamPropertySocketSecurityLevel,
kCFStreamSocketSecurityLevelTLSv1);

self.inputStream = (NSInputStream *)readStream;
self.outputStream = (NSOutputStream *)writeStream;

CFReadStreamOpen(readStream);
CFWriteStreamOpen(writeStream);
}

On Jan 24, 8:16 am, Ken Thomases <k...@codeweavers.com> wrote:

Ken Thomases

unread,
Jan 24, 2011, 11:53:35 AM1/24/11
to cocoa-...@googlegroups.com
On Jan 24, 2011, at 8:34 AM, Heath wrote:

> That was it!

I'm glad I could help.

> Do you want to answer the stackoverflow question, so you can have the
> rep, or do you just want me to point to this response?

I don't have any use for StackOverflow rep. Thanks for the offer, but go ahead and do whatever. :)

Cheers,
Ken

Heath

unread,
Jan 24, 2011, 9:03:14 PM1/24/11
to cocoa-unbound
BTW, was that just a guess, or did you have insight from the
documentation somehow? I re-read all the docs on all the constants,
and I saw nothing that implied a required order.
Reply all
Reply to author
Forward
0 new messages