robbiehanson/CocoaAsyncSocket — Issue #15: Client certificate authentication
Author: AdamSelene
Created: 2012-01-05 00:17:18+00:00
State: open

GCDAsyncSocket does not allow client certificate authentication, even if the certificate is transmitted by the client.
This is because SecureTransport has a default authentication requirement set to kNeverAuthenticate and, as far as I know, there's no way to change this with GCDAsyncSocket.
Because of that, SSLCopyPeerCertificates(sslContext, &certs) will get you a nil object.

Simple patch below

GCDAsyncSocket.h:
extern NSString *const GCDAsyncSocketSSLClientSideAuthentication;

GCDAsyncSocket.m:
NSString *const GCDAsyncSocketSSLClientSideAuthentication = @"GCDAsyncSocketClientSideAuthentication";

in maybeStartTls:

// Configure SSLContext from given settings
//
// Checklist:
// 1. kCFStreamSSLPeerName
// 2. kCFStreamSSLAllowsAnyRoot
// 3. kCFStreamSSLAllowsExpiredRoots
// 4. kCFStreamSSLValidatesCertificateChain
// 5. kCFStreamSSLAllowsExpiredCertificates
// 6. kCFStreamSSLCertificates
// 7. kCFStreamSSLLevel
// 8. GCDAsyncSocketSSLCipherSuites
// 9. GCDAsyncSocketSSLDiffieHellmanParameters
// 10. GCDAsyncSocketSSLClientSideAuthentication

...
// 10. GCDAsyncSocketSSLClientSideAuthentication
if (isServer) {
value = [tlsSettings objectForKey:GCDAsyncSocketSSLClientSideAuthentication];
NSNumber *sslAuthNumber = (NSNumber *)value;
int sslAuth = [sslAuthNumber intValue];
if (sslAuth == kTryAuthenticate
|| sslAuth == kAlwaysAuthenticate
|| sslAuth == kNeverAuthenticate)
status = SSLSetClientSideAuthenticate(sslContext, sslAuth);
if (status != noErr)
{
[self closeWithError:[self otherError:@"Error in SSLSetClientSideAuthenticate"]];
return;
}
}

Then just set the tlsSettings (on the server side only) like this:
[tlsSettings setObject:[NSNumber numberWithInt:kAlwaysAuthenticate] forKey:(NSString *)GCDAsyncSocketSSLClientSideAuthentication];