无法使用自定义 CA 打开安全 websocket
Posted
技术标签:
【中文标题】无法使用自定义 CA 打开安全 websocket【英文标题】:Unable to open secure websocket using custom CA 【发布时间】:2013-11-26 22:32:11 【问题描述】:我正在编写一个 ios 应用程序,它使用 socket.io(socket.io-objc 库)连接到本地和远程服务器。我与远程服务器的连接已经使用 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】:我从未听说过能够将证书添加到应用程序的受信任锚点。通常,这只能通过 iPhone 配置实用程序在设备级别完成。这就是您所说的“手动”吗? (即安装它以便 Safari 也支持它?)如果您仔细阅读您链接的博客文章的 cmets,您会注意到 Heath(他是一个非常聪明的人,所以在不同意他之前我会小心) ,请注意:
我不向钥匙串添加证书。我正在创建一个 SecTrust 对象并使用它来验证连接。您只能使用 iPhone 配置实用程序将证书添加到钥匙串。除非您向钥匙串添加证书,否则我怀疑 NSURLConnection 会正常工作。
这符合我的经验和测试。 (我不知道他为什么说“接下来,您可以将您的证书添加到您的应用程序的钥匙串中。当您希望 iOS 为您创建的每个新套接字信任您的证书时,这是合适的。”)
根据我的经验,您必须为NSURLConnection
实现身份验证委托方法并自己执行SecTrustEvaluate
。 Here's an example of that.
记住,钥匙链真的只有一个;里面只是有访问组,使它看起来像你有一个私人钥匙串。而且,据我所知,该钥匙串中只有一个受信任的锚点列表,供所有人共享。
这对你使用 socket.io 没有多大帮助,因为它不能让你访问它的 NSURLConnection
委托方法。您必须修改 socket.io 以接受信任锚。
您可能会发现演示文稿Practical Security 很有用。从第 5 页开始。这就是上面示例代码的来源。
【讨论】:
以上是关于无法使用自定义 CA 打开安全 websocket的主要内容,如果未能解决你的问题,请参考以下文章