objective-c - 为什么 CFStream 不使用 TLS 1.3?
问题描述
我试图弄清楚为什么运行 iOS 14 的 iPhone 不使用 TLS 1.3 连接到兼容的网络服务器。
相关代码为:
- (void) streamOpened:(NSStream *)stream {
NSDictionary *settings = @{
(__bridge NSString *)kCFStreamSSLValidatesCertificateChain: (__bridge NSNumber *)kCFBooleanFalse
};
CFReadStreamSetProperty((CFReadStreamRef)inputStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);
CFWriteStreamSetProperty((CFWriteStreamRef)outputStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);
}
完整的源代码可以在这里看到:https ://github.com/tls-inspector/tls-inspector/blob/app-store/CertificateKit/Getters/CKAppleCertificateChainGetter.m
我尝试使用kCFStreamSSLLevel
set to指定 SSL 级别,kCFStreamSocketSecurityLevelTLSv1_3
但没有做任何事情。
如果我使用 OpenSSL 进行连接,它使用 TLS 1.3,我可以通过数据包捕获验证这一点,但使用 CFStream 它坚持使用 1.2。
解决方案
简短的回答是您最终使用了不支持 TLS 1.3 的已弃用 API。
下面给出了详细说明潜在解决方案的长答案。
我试图解决这个问题,CFStream
但没有成功。
这可能是可能的。问题是你最终会像你一样在低级别使用SSLConnectionRef
和朋友,在更高级别使用NSInputStream
和NSOutputStream
和朋友,在某些时候你会遇到这个https://developer.apple.com/documentation/security/ secure_transport?language=objc旧版 API。
在该页面上,它提到该 API 已被 Network 框架取代,这正是我建议您应该使用的。我希望也能快速实施一个解决方案,但它需要比 SO 更多的返工,所以我把它留在那里。
但是,这里有一些建议,基本上是我希望实施的想法。
和以前一样,有两个级别。
在较低级别,您最终会使用nw_
and 系列,但我会说不要那样做。某些特殊需求可能需要它,并且您的应用程序可能属于该类别,但请注意,更高级别是建立在此之上的。
在更高的层次上,这就是我认为你的解决方案所在的地方,你最终会使用NSURL
和朋友。你这里的 goto 人可能是NSURLSession
,但实施将决定这一点。我试图给出一个大纲,您可以查看我的代码以获取更多详细信息,但我认为从这里开始您将处于更好的实施位置。
我希望将您的旧流代码连接到 NSURLSession 但是当失败时我停止了。这可能有点乐观,我认为它需要更认真的返工,但各种代表(NSURLSessionDelegate、NSURLSessionTaskDelegate、NSURLSessionStreamDelegate 等)似乎已经准备好等待您的解决方案,我认为这不是很多实际工作。
我的尝试中最相关的代码片段如下。这会打开 TLS 1.3,我试图围绕这个实现。
// Some configuration
NSURLSessionConfiguration * config = NSURLSessionConfiguration.ephemeralSessionConfiguration;
// Note this one!!!
config.TLSMaximumSupportedProtocol = kTLSProtocolMaxSupported;
NSURLSession * urlSession = [NSURLSession sessionWithConfiguration:config
delegate:self
delegateQueue:NSOperationQueue.currentQueue];
从那时起,我尝试重用您的流代码,但老实说,我认为最终的解决方案甚至可能不再使用流,而是仅依赖于使用正确的委托。请原谅我在这一点上感到兴奋,但我怀疑您将能够因此大大简化您的代码。
我喜欢你的应用程序 - 它非常精美,我期待你解决这个问题。我也喜欢玩弄它,但现在这是我的贡献。
第一次尝试
我看了你的代码——它需要对 TLS 1.3 进行一些修改。我试图这样做,但我现在正在重写该课程,所以我停止了。你可以做到,但是,我不能保证它会起作用!
无论如何,这里有一些想法。
首先是现有代码。只是一些 - 咳咳 - 观察,没什么大不了的......
请注意,streamOpened
无论触发哪个流,您都将应用设置。我相信,委托将两次发送消息,一次用于输入,一次用于输出流。虽然在这里看起来你应该小心并不重要,因为这可能会在另一种情况下引入一些严重的错误。
另外,我认为您需要在打开流之前对其进行配置,但这没有任何区别。如果您在打开流之前performTaskForURL
或之后在其中配置流,streamOpened
则无关紧要。
我玩了一下配置。您无需在输出流上设置一个,只需在输入上设置。唯一需要的键是您已经设置的键。无论我做什么,我都无法得到任何区别。
其次,我 - 嗯 -认为的解决方案将在这里工作。
您需要配置 URL 会话。所以我做的是以下
- (void) performTaskForURL:(NSURL *)url{
queryURL = url;
// Some configuration
NSURLSessionConfiguration * config = NSURLSessionConfiguration.ephemeralSessionConfiguration;
// Note this one!!!
config.TLSMaximumSupportedProtocol = kTLSProtocolMaxSupported;
NSURLSession * urlSession = [NSURLSession sessionWithConfiguration:config
delegate:self
delegateQueue:NSOperationQueue.currentQueue];
// Just code to test the idea, not production ready I know
NSURLSessionStreamTask * streamTask = [urlSession streamTaskWithHostName:url.host
port:443];
[streamTask captureStreams];
}
- (void)URLSession:(NSURLSession *)session
streamTask:(NSURLSessionStreamTask *)streamTask
didBecomeInputStream:(NSInputStream *)inputStreamUrl
outputStream:(NSOutputStream *)outputStreamUrl
{
// I was hoping to get away with this,
// just setting your streams equal to the
// URL stream task streams but it did not
// work ... problem is you need more of the
// stream task delegate methods I believe
inputStream = inputStreamUrl;
outputStream = outputStreamUrl;
// This is some left over code from your performTaskForURL message
// Here you can see how I toyed with the stream configuration
// Configure here before it is opened
// Pretty much your current streamOpened message
// Note only input needs be configured (fwiw)
[self configureStream:inputStream];
inputStream.delegate = self;
outputStream.delegate = self;
[outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream open];
[inputStream open];
// I was hoping this would just work but I think it needs more work
}
这里的想法是配置一个 URL 会话,kTLSProtocolMaxSupported
然后创建一个流任务。现在这就是我想停下来并认为你更擅长走得更远的地方。我希望我可以获取流并将它们返回到您的代码中,但它不起作用,现在我不会更进一步。
我无法测试我的想法,因为我需要将更多的东西连接到NSURLSessionStreamDelegate
你的类现在也实现的东西上。我认为你已经在课堂上做了同样的事情,但是对于流。
现在,再次,我可能是错的,并且想在发布之前进行测试,但是要么看看这是否可行,然后我认为您需要例如实现委托方法,例如URLSession:task:didReceiveChallenge:completionHandler:
.
我认为你已经在你的代码中做了这样的事情,但这就是我在这里停下来的原因,因为我认为你会更好地判断这个想法。
我已经玩弄了一些但没有成功 - 但我认为你需要在这里使用 NSURLSession ,甚至可能代替套接字。
推荐阅读
- python - TypeError:Update_Profile() 缺少 1 个必需的位置参数:'self'
- java - 自动生成 CHANGELOG.md 文件
- trace32 - Trace32 - PBI=MCIServer 非法逗号错误
- c - 实现一个名为翻转的函数;它将一个数字作为输入并翻转它的最后 N 个数字
- c++ - Sqlite3 C++ 数据库被锁定
- java - 如何将 MySQL 数据库注入项目文件夹
- arrays - 如何在 swift 中一次在 Firestore 文档中设置多个字段
- java - 在 setOnEditCommit JavaFX 之后禁用 TableCell
- r - Jtools-错误消息-没有适用于“summ”的方法应用于类“list”的对象
- android - Android 自定义 SeekBar - 进度不跟随拇指