带有客户端身份validation的GCDAsyncSocket

我一直在使用CocoaAsyncSocket将数据发送到没有SSL的服务器。 现在服务器端已经实现了带有客户端身份validation的SSL / TLS。 为了在我们的应用程序中实现这一点,我得到了以下三个文件:

  1. CA-chain.cert.pem
  2. 客户test.cert.pem
  3. 客户test.key.pem

我将文件转换为iOS可读格式,如下所示:

  1. ca-chain.cert.pem到ca-cert.cer
  2. client-test.cert.pem到client_cert.cer
  3. client-test.key.pem到client_key.p12

我已经让它工作到SSL。 但是客户端身份validation有问题。

这是我的代码:

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; } 

我一直在努力与客户端身份validation两天。 我现在得到这个错误:

 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's SecureTransport.h} 

我确实读过CocoaAyncSocket库与manualy信任评估的客户端身份validation有问题。 我尝试了这里提到的解决方法: 支持客户端身份validation与手动信任评估仍然没有运气。 我找不到我错过的东西。

提前致谢! -Uma

代码一切都很好。 我希望这有助于寻找答案的人。 然而问题是文件转换。 当我使用来自其他人的转换文件时,它起作用了。