我试图弄清楚为什么运行iPhone 14的iOS不使用TLS1.3连接到兼容的web服务器。
有关守则是:
- (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设置为kCFStreamSocketSecurityLevelTLSv1_3的SSL级别,但这没有起到任何作用。
如果我使用OpenSSL进行连接,它使用TLS1.3,我可以通过数据包捕获来验证这一点,但是使用CFStream,它将保持在1.2。
发布于 2020-10-16 16:22:23
简单的回答是,您最终使用的是不支持TLS1.3的不推荐API。
下面给出了详细说明潜在解决方案的详细答案。
我试图用CFStream解决这个问题,但没有成功。
这可能是可能的。问题是,您最终会像使用SSLConnectionRef和朋友一样,在较低的级别使用NSInputStream和NSOutputStream以及朋友,而在更高的级别上,您会遇到这个https://developer.apple.com/documentation/security/secure_transport?language=objc遗留API。
在那一页上,它提到了API被网络框架所取代,实际上这就是我建议您应该使用的内容。我希望也能快速地实现一个解决方案,但它需要更多的返工,所以我把它放在这里。
不过,谨此提出一些建议,基本上是我希望落实的想法。
和以前一样,有两个层次。
在较低的级别,您最终使用的是nw_和家庭,但我要说的是,不要这样做。它可能需要一些专门的需求,您的应用程序可能在这一类别,但仍然要注意,更高的层次是建立在此之上。
在更高的层次上,这就是我认为您的解决方案所在,您最终使用的是NSURL和朋友。这里的goto可能是NSURLSession,但是实现将决定这一点。我试图给出一个大纲,您可以查看我的代码,以获得更多的细节,但我认为从现在开始,您将能够更好地实现。
在这方面,我希望将遗留的流代码连接到NSURLSession,但当失败时,我停止了。这可能有点乐观,我认为这需要更严肃的重做,但各种代表(NSURLSessionDelegate、NSURLSessionTaskDelegate、NSURLSessionStreamDelegate等)似乎已经准备好等待您的解决方案,我不认为这实际上是很多工作。
下面是我的尝试中最相关的代码片段。这打开了TLS1.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都将应用这些设置。委托将向我传递两次信息,一次用于输入,一次用于输出流。虽然这里看起来并不重要,但您应该小心,因为这可能会在另一种情况下引入一些严重的bug。
另外,我认为您需要在流打开之前配置它们,但这并没有造成任何不同。如果在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
}这里的想法是使用kTLSProtocolMaxSupported配置一个URL会话,然后创建一个流任务。这就是我想要停下来的地方,我认为你更擅长于更进一步。我希望我能得到流并将它们扔回您的代码中,但是它没有工作,目前我没有更进一步。
我无法测试我的想法,因为我需要将更多的东西与您的类现在也实现的NSURLSessionStreamDelegate连接起来。我认为你已经在课堂上做了同样的事情,但是对于流来说。
现在,我可能又错了,我想在发布之前进行测试,但要么看看这是否可行,然后我认为您需要实现委托方法,例如URLSession:task:didReceiveChallenge:completionHandler:。
我认为您已经在代码中做了类似的事情,但这就是为什么我要在这里停下来,因为我认为您会更好地判断这个想法。
我已经尝试了更多,但没有成功--但我认为您需要在这里使用NSURLSession,甚至可以代替套接字。
https://stackoverflow.com/questions/64300673
复制相似问题