0

First the server side: There is an internal reachable apache server with several virtual hosts. For http (sans 's'!) requests, I use the IP for the URL and add the hostname in the Host-Headerfield.

That works quite good.

But when I make an SSL connection I run into problems which seems to be releated by SNI.

I found this Overriding TLS Chain Validation Correctly and implemented it in my code.

So I updated the trust in

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

but I still get a 400 from the server.

UPDATE: URLSession does support SNI but my problem is that I need to add an additional or change the hostname in the SSLHandshake.

So first a short description of the server: The Server is an Apache-server that is only reachable via IP but it has multiple vhosts which are locally available via the hostname but when I connect to them from an external device like an iPhone I have to add the hostname of the vhost in the Host-Headerfield.

So what I do is: I create an URLRequest with an IP-base URL and then add the HOST Headerfield with hostname

if let url = URL("https://192.168.178.54:8890") {
    var request = URLRequest(url: url)
    request.addValue("foobar:8890", forHTTPHeaderField: "Host")
    …
}

This works perfekt for non-secure http-Requests but as soon as https is used the server returns the "400 Bad request" and the http-ssl-error.log contains the following error:

[Tue Jul 11 09:35:51 2017] [error] Hostname 192.168.178.54 provided via SNI and hostname foobar provided via HTTP are different

This is because by default the SSLHandshake uses value provided in the URL and in my case this is the IP.

What I now try to figure out is how to provide a different hostname in the SSLHandshake or, alternatively, provide something like an own DNS resolver where I can still use a hostname-base URL, but iOS gets the routing straight.

MatzeLoCal
  • 392
  • 3
  • 14
  • SNI is natively supported by NSURLSession. You should not need to make any modifications to your code for that to work correctly. What does `openssl s_client -connect hostname.com:443` say about your server? – dgatwood Jul 11 '17 at 19:56
  • Thanks for the comment. The answer from my server guy was a bit misleading. Yes, URLSession supports SNI and it works in normal cases but I have to change the hostname in the SSLHandshake … and that's not possible with URLSession. I will update my OP to make it more clear – MatzeLoCal Jul 12 '17 at 06:52
  • Post some of the code for how you're updating the challenge. – dgatwood Jul 12 '17 at 14:24
  • The problem has nothing to do with `func urlSession(_ session:didReceivechallenge:completionHandler:)` it has todo with the SSL-Handshake which happens before the URLSession kicks in. I opened a TSI and got the info from Apple which does not sounds good: _The problem at the API level is that the URL is that the “host” is retrieved by two different system components (the TLS engine and the HTTP protocol implementation), but you can really only control one of them (the HTTP implementation through URLProtocol)_ – MatzeLoCal Jul 12 '17 at 19:27
  • Any chance you solved this and remember how ? – whoopdedoo Apr 17 '19 at 16:19
  • Hi, I received two answers by Apple and in short the answer is: It won't work. I will put more info in my answer to the problem. – MatzeLoCal Apr 23 '19 at 10:32

1 Answers1

0

First how we solved it: The Server-guys finally did their job right and did not messed around with botchy settings.

Back the I also posted my question in the Apple Dev Forums

And I also received this from my TSI:

passed your incident to me because I generally take the lead on both NSURLSession and TLS issues here in DTS (I was out of the office when your incident originally came in).

Coming back to your technical issue it seems that I responded to you via the DevForums thread that you created for this.

https://forums.developer.apple.com/thread/82179

That response was rather brief but it did cover the salient points:

  • There’s no way to configure the SNI name at the NSURLSession level

  • My recommended alternative is to use .local DNS names

As noted above my DevForums response was rather brief so if you have any follow up questions about the latter I’d be happy to answer them here.

You /can/ override the SNI name at lower levels in the networking stack, that is, CFSocketStream (accessed via the NSSStream and CFStream APIs) and Secure Transport.  In theory you could implement your own HTTP protocol layer within your NSURLProtocol subclass, using these APIs for the TLS-over-TCP side of things, but I /strongly/ recommend against that because it’s a huge amount of work.

Share and Enjoy -- Quinn "The Eskimo!" Apple Developer Relations, Developer Technical Support, Core OS/Hardware

MatzeLoCal
  • 392
  • 3
  • 14