带有客户端身份验证的GCDAsyncSocket

时间:2017-03-13 21:12:16

标签: ios cocoaasyncsocket ssl-client-authentication

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

  1. CA-chain.cert.pem
  2. 客户test.cert.pem
  3. 客户test.key.pem
  4. 我将文件转换为iOS可读格式,如下所示:

    1. ca-chain.cert.pem to ca-cert.cer
    2. client-test.cert.pem到client_cert.cer
    3. client-test.key.pem to client_key.p12
    4. 我的工作直到SSL。但是客户端身份验证有问题。

      这是我的代码:

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

      我一直在努力进行客户端身份验证两天。我现在得到这个错误:

      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信任评估的客户端身份验证有问题。我尝试了这里提到的解决方法:Support for client side authentication with manual trust evaluation仍然没有运气。我找不到我想念的东西。

      提前致谢! -Uma

1 个答案:

答案 0 :(得分:3)

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