How to get custom NSURLProtocol working with SNI

1k Views Asked by At

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.

1

There are 1 best solutions below

0
MatzeLoCal On

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