GCDAsyncSocket with client authentication

I use CocoaAsyncSocket to send data to our server without SSL. Now the server side has implemented SSL / TLS with client authentication. To implement this in our application, I was provided with the following three files:

  • cha-chain.cert.pem
  • client-test.cert.pem
  • client-test.key.pem

I converted the files to readable iOS formats as shown below:

  • ca-chain.cert.pem for ca-cert.cer
  • client-test.cert.pem for client_cert.cer
  • client-test.key.pem for client_key.p12

It works for me before SSL. But there were problems with client authentication.

Here is my code:

didConnectToHost:

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port; { // Configure SSL/TLS settings NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithCapacity:3]; // Allow self-signed certificates CFArrayRef certsArray = [self loadCertificates]; [settings setObject:@0 forKey:GCDAsyncSocketSSLProtocolVersionMax]; [settings setObject:[NSNumber numberWithBool:YES] forKey:GCDAsyncSocketManuallyEvaluateTrust]; [settings setObject:(id)CFBridgingRelease(certsArray) forKey:GCDAsyncSocketSSLCertificates]; [sock startTLS:settings]; } 

didReceiveTrust:

 - (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler { NSString *caCertPath = [[NSBundle mainBundle] pathForResource:@"ca-cert" ofType:@"cer"]; NSData *caCertData = [NSData dataWithContentsOfFile:caCertPath]; NSString *clientCertPath = [[NSBundle mainBundle] pathForResource:@"client_cert" ofType:@"cer"]; NSData *clientCertData = [NSData dataWithContentsOfFile:clientCertPath]; OSStatus status = -1; SecTrustResultType result = kSecTrustResultDeny; if(caCertData && clientCertData) { SecCertificateRef cert1; cert1 = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) caCertData); SecCertificateRef cert2; cert2 = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) clientCertData); const void *ref[] = {cert1,cert2}; CFArrayRef ary = CFArrayCreate(NULL, ref, 2, NULL); SecTrustSetAnchorCertificates(trust, ary); status = SecTrustEvaluate(trust, &result); } else { NSLog(@"local certificates could not be loaded"); completionHandler(NO); } if ((status == noErr && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified))) { completionHandler(YES); } else { CFArrayRef arrayRefTrust = SecTrustCopyProperties(trust); NSLog(@"error in connection occured\n%@", arrayRefTrust); completionHandler(NO); } } 

loadCertificates:

 -(CFArrayRef) loadCertificates { NSString *clientKeyPath = [[NSBundle mainBundle] pathForResource:@"client_key" ofType:@"p12"]; NSData* clientKeyData = [NSData dataWithContentsOfFile:clientKeyPath]; NSLog(@"key : %@",[[NSString alloc] initWithData:clientKeyData encoding:NSASCIIStringEncoding]); CFDataRef inPKCS12Data = (CFDataRef)CFBridgingRetain(clientKeyData); CFStringRef password = CFSTR("_mypassword_"); const void *keys[] = { kSecImportExportPassphrase }; const void *values[] = { password }; CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL); CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); OSStatus securityError = SecPKCS12Import(inPKCS12Data, options, &items); CFRelease(options); CFRelease(password); if(securityError == errSecSuccess) NSLog(@"Success opening p12 certificate."); CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0); SecIdentityRef myIdent = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity); NSString *clientCertPath = [[NSBundle mainBundle] pathForResource:@"client_cert" ofType:@"cer"]; NSData *clientCertData = [NSData dataWithContentsOfFile:clientCertPath]; SecCertificateRef clientCert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) clientCertData); //SecIdentityRef certArray[1] = { myIdent }; const void *ref[] = {myIdent, clientCert}; CFArrayRef myCerts = CFArrayCreate(NULL, ref, 2, NULL); // NSString *caCertPath = [[NSBundle mainBundle] pathForResource:@"ca-cert" ofType:@"cer"]; // NSData *caCertData = [NSData dataWithContentsOfFile:caCertPath]; // // SecCertificateRef caCert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) caCertData); // // const void *ref[] = {clientCert, myIdent, caCert}; // CFArrayRef myCerts = CFArrayCreate(NULL, ref, 3, NULL); return myCerts; } 

I tried client authentication for two days. I get this error:

 2017-03-13 15:35:40.777 MPS[79612:1478858] GCDAsyncSocket socketDidDisconnect Error - Error Domain=kCFStreamErrorDomainSSL Code=-9806 "(null)" UserInfo={NSLocalizedRecoverySuggestion=Error code definition can be found in Apple SecureTransport.h} 

I read that the CocoaAyncSocket library has a problem with client authentication with manual trust verification. I tried a workaround as mentioned here: Client-side authentication support with manual trust control Still no luck. I could not find what I was missing.

Thanks in advance! -Uma

+3
source share
1 answer

All is well with the code. Hope this helps someone find the answer. However, the problem was file conversion. When I used the converted files from another person, it worked.

+1
source

Source: https://habr.com/ru/post/1212955/


All Articles