URLSession didReceiveChallenge failing on iOS 17

We're seeing server trust failures with iOS 17 that we don't see with iOS 16, particularly in debugging, when we build with Xcode 15. We handle

func urlSession(_ session: URLSession,
                didReceive challenge: URLAuthenticationChallenge,
                completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)

and choose to deal with recoverable server trust failures of particular kinds ourselves. After our checks we end up calling the completion handler:

  let credential = URLCredential(trust: serverTrust)
  completionHandler(.useCredential, credential)

And everything continues.

This is working on macOS Venture and earlier and iOS 16 and earlier. It also works if we install our current release build on iOS 17. If we build with Xcode 15 and test on iOS 17 then calling the completion handler with .useCredential ends up failing with a -1200 error, and a message about a recoverable trust failure.

Has anyone else seen this behavior? Does anyone know if this is related to just Xcode 15, or to Xcode 15 + an interaction with iOS 17? Maybe the SDKs used with Xcode 15 are being stricter? In any case it would seem that saying .useCredential should cause it to .use the credential...

Answered by DTS Engineer in 755599022

Are you perhaps being bitten by the ATS change documented in the iOS & iPadOS 17 Beta Release Notes?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks. I'll take a look.

What we need to validate is whether adding all IP addresses to the exception domains means that no cert validation will be done.

If so, then that's not quite what we want. Prior to iOS 17 we'd

  • get a callback with a recoverable trust failure
  • check to see that it was a hostname issue
  • see if the host name that we know is in the certificate, and continue if so, cancel if not.

Well, 0.0.0.0/0 does not work. Specifying a specific subnet or IP address works.

This is true with a lot of other Network Extension APIs. 0.0.0.0/0 isn't treated as an address, it's treated like a flag. You can't specify exclusions on the default subnet for example.

If you define both 128.0.0.0/1 and 0.0.0.0/1, which effectively covers the same address space, it works as expected.

Someone really dropped the ball on default network handling in the Network Extension code though--if it can be specified as a CIDR address it should be treated as a CIDR address, and it's not.

Well, 0.0.0.0/0 does not work

I’d appreciate you filing a bug about that; please post your bug number, just for the record.

If you define both 128.0.0.0/1 and 0.0.0.0/1, which effectively covers the same address space, it works as expected.

Cool. I’m glad you found that workaround.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Well, 0.0.0.0/0 does not work

I asked about this internally — because I absolutely expected that to work — and it seems that, yep, it’s a bug (r. 114040682). I have no info to share as to when it’ll be fixed, but the workaround you’re using seems fine.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Cool. Sounds like I don't need to file another issue about that, unless it would help with finding out when the problem is fixed.

I hope they're looking at fixing this issue throughout the Network Extension code, not just for the ATS exclusions.

Kevin


kjbrock icloud com

Sounds like I don't need to file another issue about that

Correct.

I hope they're looking at fixing this issue throughout the Network Extension code, not just for the ATS exclusions.

This is specific to ATS. AFAIK we don’t use CIDR notation in NE APIs.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

If the defaultRoute is set in IPv4Settings.includedRoutes then exclusions don't work.

In the documentation it says that defaultRoute is "A convenience method for creating the default IPv4 route", which of course is 0.0.0.0/0.

Any addresses set in excludedRoutes continue to be tunneled. If we set 1/1 & 128/1 in IPv4Settings.includedRoutes things work, and excludedAddresses are excluded properly. This is similar enough to the behavior with ATS that I'd suspect similar underlying logic.

This is similar enough to the behavior with ATS that I'd suspect similar underlying logic.

… and you’d be wrong (-: These are different subsystems at opposite ends of our networking stack.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

URLSession didReceiveChallenge failing on iOS 17
 
 
Q