无法使用自定义CA打开安全websocket

时间:2013-11-26 22:32:12

标签: ios ssl websocket

我正在编写一个使用socket.io(socket.io-objc库)连接到本地和远程服务器的iOS应用程序。我与远程服务器的连接已经没有任何问题地使用TLS。远程服务器具有由知名CA签名的证书。现在我想要使用本地连接。但是,这些本地证书不可能由着名的CA签名。

到目前为止,我已经生成了一个自定义CA证书,并用它来签署本地服务器的证书。我相信这是有效的,因为如果我手动将CA证书安装到我的iPad上,我就可以连接到服务器了。

现在,我正在尝试使用this article作为参考在应用程序中自动安装CA证书。我遇到的问题是,虽然看起来我可以成功将证书添加到我的应用程序的钥匙串,但我的套接字连接似乎没有使用它。

启动时,我的应用会安装CA:

NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSData *iosTrustedCertDerData = [NSData dataWithContentsOfFile:[bundle pathForResource:@"myRootCA" ofType:@"der"]];
SecCertificateRef certificate = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef) iosTrustedCertDerData);

CFDictionaryRef dict = (__bridge CFDictionaryRef)([NSDictionary dictionaryWithObjectsAndKeys:
                        (__bridge id) (kSecClassCertificate), kSecClass,
                        certificate, kSecValueRef,
                        nil]);

OSStatus err = SecItemAdd(dict, NULL);
if (err == noErr) {
    NSLog(@"####### IT WORKS!!!!!!!!!");
}
else if (err == errSecDuplicateItem) {
    NSLog(@"###### IT WAS ALREADY THERE!!!");
}
else {
    NSLog(@"####### IT BROKEN!!!!!!!!");
}

这是第一次出现,它打印出“IT WORKS”。现在它打印出“它已经在那里”。这是预期的。然后,当我尝试连接时,我就像普通的

一样打开我的socket.io连接
SocketIO* socketIO = [[SocketIO alloc] initWithDelegate:self];
socketIO.useSecure = YES;
[socketIO connectToHost:url onPort:port];

这会导致错误:

  

此服务器的证书无效。您可能正在连接到假装为“myserver.local”的服务器,这可能会使您的机密信息面临风险。

同样,如果我手动安装证书,那么一切正常。我的所有搜索都是如何以编程方式将证书点添加/信任回SecItemAdd。但这似乎对我不起作用。是否可以使用管理套接字连接的socket.io-obj和SocketRocket库来添加/信任自定义CA证书?

注意:我不想完全禁用证书验证,也不想接受所有自签名证书。如果可能,我宁愿只接受由我的自定义CA(和默认的可信CA)签名的证书。

1 个答案:

答案 0 :(得分:1)

我从未听说过能够将证书添加到应用程序的可信锚点。通常,这只能通过iPhone配置实用程序在设备级别完成。这就是“手动”的意思吗? (即安装它以便Safari也会尊重它?)如果你读到你链接的博客文章的评论,你会注意到Heath(谁是一个非常聪明的人,所以在我不同意他之前我很小心) ,注意到:

  

NOT 在钥匙串中添加证书。我正在创建一个SecTrust对象并使用它来验证连接。您只能使用iPhone配置实用程序将证书添加到钥匙串。除非你在钥匙串上添加证书,否则我怀疑NSURLConnection会正常工作。

这符合我的经验和测试。 (我不知道他为什么说“接下来,你可以将你的证书添加到你的应用程序的钥匙串。当你希望iOS为你创建的每个新套接字信任你的证书时,这是合适的。”)

根据我的经验,您必须为NSURLConnection实施身份验证委托方法并自己执行SecTrustEvaluateHere's an example of that.

请记住,确实只有一个钥匙串;只有访问组进入它,使你看起来像你有一个私人钥匙串。据我所知,在每个人共享的钥匙串中只有一个可靠的锚列表。

这对socket.io没有多大帮助,因为它不允许您访问其NSURLConnection委托方法。您必须修改socket.io以接受信任锚。

您可能会发现演示文稿Practical Security很有用。从第5页开始。这是上面的示例代码来自的地方。