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

标签 ios ssl websocket

我正在编写一个 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)方法并自行执行 SecTrustEvaluateHere'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/

相关文章:

IOS 8 按钮背景图像检查不起作用

javascript - 为什么我不能在 UIWebView 中关闭或关闭 Javascript 警报?

ssl - 如何在 ibm 云上安装 LetsEncrypt 证书?

PHP/Ratchet websockets - 无法监听 "tcp://0.0.0.0:443"

ios - 在 iOS 上通过 twitter 登录并在我的服务器上进行身份验证

android - 拦截 Android GMail SSL 连接

python ssl问题打开证书文件

JavaScript 函数阻止 Web 套接字并导致同步问题和延迟

python-3.x - Websocket 高速公路 Python 客户端 : how to connect to server using server and client certificates?

ios - iOS AudioUnit播放crack啪声问题(swift)