2

I am able to connect to the desired socket with IP and port.

- (void)socket:(GCDAsyncSocket *)sender didConnectToHost:(NSString *)host port:(UInt16)port {

    [sender startTLS:nil];

    if(self.createTCPSocketHelperDelegate && @selector(returnConnectedTCPSocket:forNASWithMacAddress:))
    {
        [self.createTCPSocketHelperDelegate returnConnectedTCPSocket:sender forNASWithMacAddress:_macAddress];
    }
}

I am sending TLS settings dictionary nil for as it uses default settings. It gives me the error as follows

Error Domain=kCFStreamErrorDomainSSL Code=-9806 "The operation couldn’t be completed. (kCFStreamErrorDomainSSL error -9806.)" UserInfo=0x17d92420 {NSLocalizedRecoverySuggestion=Error code definition can be found in Apple's SecureTransport.h}

I couldn't get what's wrong going on there. Please help me to provide some sample code which connect to SSL server and use TCP/TLS protocol.

Help would be appreciated. Thank you in advance. :)

0

1 Answer 1

5

I got the issue. Basically I couldn't complete SSL handshake, I found the way as follows:

Initialize GCDAsyncSocket socket and connect to IP and Port as follows,

NSError *error;

_gcdAsyncTCPSocket  = [[GCDAsyncSocket alloc] initWithDelegate:self
                                                 delegateQueue:dispatch_get_main_queue()];

_gcdAsyncTCPSocket.delegate = self;

_ipAddress = ipAddress;

_tcpPortNumber = portNumber;

if(![_gcdAsyncTCPSocket connectToHost:ipAddress onPort:portNumber withTimeout:30 error:&error])
{
    if(self.createTCPSocketHelperDelegate && @selector(failedToCreateTCPSocket))
    {
        [self.createTCPSocketHelperDelegate failedToCreateTCPSocket];
    }
}else {

    NSMutableDictionary *settings = [[NSMutableDictionary alloc] init];

    [settings setObject:[NSNumber numberWithBool:YES]
                 forKey:GCDAsyncSocketManuallyEvaluateTrust];

    [_gcdAsyncTCPSocket startTLS:settings];
}

When you set GCDAsyncSocketManuallyEvaluateTrust it gives a call to delegate method

- (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler

In which I have evaluate the server's self signed certificate with the local certificate. If its equal then completionHandler(YES) otherwise completionHandler(NO) as follows:

- (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler {
NSLog(@"didReceiveTrust");

//server certificate
SecCertificateRef serverCertificate = SecTrustGetCertificateAtIndex(trust, 0);
CFDataRef serverCertificateData = SecCertificateCopyData(serverCertificate);

const UInt8* const serverData = CFDataGetBytePtr(serverCertificateData);
const CFIndex serverDataSize = CFDataGetLength(serverCertificateData);
NSData* cert1 = [NSData dataWithBytes:serverData length:(NSUInteger)serverDataSize];


//local certificate
NSString *localCertFilePath = [[NSBundle mainBundle] pathForResource:@"LocalCertificate" ofType:@"cer"];
NSData *localCertData = [NSData dataWithContentsOfFile:localCertFilePath];
CFDataRef myCertData = (__bridge CFDataRef)localCertData;


const UInt8* const localData = CFDataGetBytePtr(myCertData);
const CFIndex localDataSize = CFDataGetLength(myCertData);
NSData* cert2 = [NSData dataWithBytes:localData length:(NSUInteger)localDataSize];


if (cert1 == nil || cert2 == nil) {
    NSLog(@"Certificate NULL");
    completionHandler(NO);
    return;
}


const BOOL equal = [cert1 isEqualToData:cert2];

if (equal) {

    NSLog(@"Certificate match");
    completionHandler(YES);

}else{

    NSLog(@"Certificate not match");
    completionHandler(NO);
}
}

If certificates matches completionHandler(YES) it will call delegate

- (void)socketDidSecure:(GCDAsyncSocket *)sock {

NSLog(@"socketDidSecure");

_uploadSocket = sock;

//Do your stuff after this
}

Hope it will help someone to deal with SSL and GCDAsyncSocket. Happy coding!!

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for this detailed answer. Is having a local certificate absolutely necessary? Is there another route where comparison with a saved local certificate isn't necessary?
Having a local cert to compare to is only necessary if you have a self-signed cert on the server. The question doesn't ask about self-signed certs so I don't think this answer is relevant.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.