使用由自定义CA签名的证书的CocoaHTTPServer和SSL,NSURLConnection失败

时间:2014-01-03 16:36:45

标签: ios ssl ssl-certificate cocoahttpserver

我有一个小应用程序,里面有CocoaHttpServer选址。我想只为环回调用启用它,我希望能够只从我的应用程序进行这些调用。不要问为什么 - 我需要它。

self.httpServer = [[HTTPServer alloc] init];
self.httpServer.port = HTTP_SERVER_PORT;
self.httpServer.interface = @"loopback";
self.httpServer.connectionClass = [HTTPSolFSConnection class];

NSError *error;
if([self.httpServer start:&error]) {
    DDLogInfo(@"Started HTTP Server on port %hu", [self.httpServer listeningPort]);
}
else {
    DDLogError(@"Error starting HTTP Server: %@", error);
}

服务器使用自定义HTTPConnection类,该类在 isSecureServer 方法中返回 YES ,并使用使用自定义CA签名的证书。

- (BOOL)isSecureServer {
    return YES;
}

- (NSArray *)sslIdentityAndCertificates {
    NSArray *result = nil;

    NSData *serverCertificateData = [[NSData alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"server" ofType:@"p12"]];

    const void *keys[] =   { kSecImportExportPassphrase };
    const void *values[] = { CFSTR("friday_internet") };
    CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);

    CFArrayRef items = NULL;
    OSStatus securityError = SecPKCS12Import((__bridge CFDataRef) serverCertificateData, options, &items);

    if (options) {
        CFRelease(options);
    }

    if (securityError == errSecSuccess) {
        CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
        SecIdentityRef identity = (SecIdentityRef) CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity);

        SecCertificateRef serverCertificate = NULL;
        SecIdentityCopyCertificate(identity, &serverCertificate);

        NSData *caCertificateData = [[NSData alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ca" ofType:@"der"]];
        SecCertificateRef caCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) caCertificateData);
        NSArray *anchorCertificates = @[ (__bridge id) serverCertificate, (__bridge id) caCertificate ];

        SecTrustResultType trustResult;
        SecTrustRef trust = (SecTrustRef) CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemTrust);
        SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef) anchorCertificates);
        SecTrustSetAnchorCertificatesOnly(trust, false);

        SecTrustEvaluate(trust, &trustResult);
        NSLog(@"SecTrustResultType: %d", trustResult);

        result = @[ (__bridge id) identity, (__bridge id) caCertificate, (__bridge id) serverCertificate ];

        if (serverCertificate) {
            CFRelease(serverCertificate);
        }
    }

    if (items) {
        CFRelease(items);
    }

    return result;
}

每次我向服务器创建NSURLConnection时,它都会记录 SecTrustResultType:4 并因错误而失败:

Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. 
You might be connecting to a server that is pretending to be “localhost” which could 
put your confidential information at risk." UserInfo=0xb93da40 
{NSErrorFailingURLStringKey=https://localhost:12345/file.txt, 
NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, 
NSErrorFailingURLKey=https://localhost:12345/file.txt, 
NSLocalizedDescription=The certificate for this server is invalid.
You might be connecting to a server that is pretending to be “localhost” which could
put your confidential information at risk., NSUnderlyingError=0xf155310 
"The certificate for this server is invalid. You might be connecting to a server
that is pretending to be “localhost” which could put your confidential information
at risk.", NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x13329720>}

我在StackOverflow上阅读了很多文章和许多问题,但它没有帮助:

  1. How do I programatically import a certificate into my iOS app's keychain and pass the identity to a server when needed?
  2. How to make iPhoneHTTPServer secure server
  3. SecTrustEvaluate always returns kSecTrustResultRecoverableTrustFailure with SecPolicyCreateSSL
  4. Unable to trust a self signed certificate on iphone
  5. https://developer.apple.com/library/ios/technotes/tn2232/_index.html#//apple_ref/doc/uid/DTS40012884-CH1-SECCUSTOMROOT
  6. https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html
  7. 有两个“黑客”可以解决问题:

    1. 我可以实现连接:NSURLConnectionDelegate的willSendRequestForAuthenticationChallenge:方法
    2. 我可以实现自定义NSURLProtocol
    3. 将CA的证书通过电子邮件发送给设备并手动信任
    4. 问题是我在我的应用程序中使用第三方库与我的服务器通信。它不使用Foundation框架,因此前两个方法不起作用。有没有办法以编程方式而不是手动发送证书?

0 个答案:

没有答案