我正在编写一个 iOS 应用程序,它使用 socket.io(socket.io-objc 库)连接到本地和远程服务器。我与远程服务器的连接已经使用 TLS,没有任何问题。远程服务器具有由知名 CA 签名的证书。现在我也想使用保护本地连接。但是,这些本地证书不可能由知名 CA 签名。
到目前为止,我已经生成了一个自定义 CA 证书并使用它来签署本地服务器的证书。我相信这是可行的,因为如果我手动将 CA 证书安装到我的 iPad 上,我就可以连接到服务器。
现在我正在尝试使用 this article 在应用程序中自动安装 CA 证书作为引用。我遇到的问题是,虽然看起来我可以成功地将证书添加到我的应用程序的钥匙串(keychain),但我的套接字连接似乎没有使用它。
启动时,我的应用会安装 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”。现在它打印出“IT WAS ALREADY THERE”。这符合预期。然后,当我尝试连接时,我只是像平常一样打开我的 socket.io 连接
SocketIO* socketIO = [[SocketIO alloc] initWithDelegate:self];
socketIO.useSecure = YES;
[socketIO connectToHost:url onPort:port];
这会导致错误:
The certificate for this server is invalid. You might be connecting to a server that is pretending to be “myserver.local” which could put your confidential information at risk.
同样,如果我手动安装证书,那么一切正常。我所有关于如何以编程方式将证书点添加/信任回 SecItemAdd 的搜索。但这似乎对我不起作用。是否可以使用管理套接字连接的 socket.io-obj 和 SocketRocket 库添加/信任自定义 CA 证书?
注意:我不想完全禁用证书验证,也不想接受所有自签名证书。如果可能,我宁愿只接受由我的自定义 CA(和默认的受信任 CA)签名的证书。
最佳答案
我从未听说过能够将证书添加到应用程序的可信 anchor 。通常,这只能通过 iPhone 配置实用程序在设备级别完成。这就是你所说的“手动”吗? (即安装它使得 Safari 也会尊重它?)如果你仔细阅读你链接的博客文章的评论,你会注意到希思(他是一个非常聪明的人,所以在我不同意他之前我很小心) ,注意到:
I’m NOT adding a cert to the keychain. I’m creating a SecTrust object and using it to authenticate the connection. You can only add certs to the keychain with the iPhone Configuration Utility. Unless you add a cert to the keychain, I doubt NSURLConnection would work properly.
这符合我的经验和测试。 (我不知道他为什么说“接下来,您可以将您的证书添加到您应用程序的钥匙串(keychain)中。当您希望 iOS 为您创建的每个新套接字信任您的证书时,这是合适的。”)
根据我的经验,您必须为 NSURLConnection
实现身份验证委托(delegate)方法并自行执行 SecTrustEvaluate
。 Here's an example of that.
请记住,实际上只有一个钥匙串(keychain);它只有访问组,使它看起来就像你有一个私有(private)钥匙串(keychain)。据我所知,该钥匙串(keychain)中只有一个可信 anchor 列表,由所有人共享。
这对您使用 socket.io 没有太大帮助,因为它不会让您访问其 NSURLConnection
委托(delegate)方法。您必须修改 socket.io 才能接受信任 anchor 。
您可以找到演示文稿,Practical Security ,有用。从第 5 页左右开始。这是上面示例代码的来源。
关于ios - 无法使用自定义 CA 打开安全的 websocket,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20229391/