Background Transfer Service and Client Certificates

I can't get NSURLSession background tasks to use client certificates.


I have a simple app that creates an NSURLSessionDownloadTask from an NSURLSession that uses NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(...).

I have a custom delegate that implements:

"func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void)". For NSURLAuthenticationMethodServerTrust, I accept any server. For NSURLAuthenticationMethodClientCertificate, I have a hardcoded PKCS12 bundle with a single certificate and key from which I successfully create an NSURLCredential (using SecPKCS12Import), then pass that credential to the completion handler with .UseCredential.

At runtime, I get the didReceiveChallenge callback for ClientCertificate, then another for NSURLAuthenticationMethodServerTrust, then URLSessionDidFinishEventsForBackgroundURLSession right away without completing the TLS handshake.

If I change the NSURLSessionConfiguration to use NSURLSessionConfiguration.defaultSessionConfiguration(), the client cert is presented correctly and the download proceeds.

Both tests are done with the app in the foreground.

I can't get NSURLSession background tasks to use client certificates.

This is currently not possible. There are issues with passing the credential from your app to

nsurlsessiond
that make this tricky to implement. I filed a bug about this a while back (r. 17277089). At that time
nsurlsessiond
would crash when you tried to do this , which was pretty crazy. I believed the crash is now fixed, but there’s still no way to achieve your actual goal.

You should definitely file your own bug about this, with an explanation as to how this bug is affecting your product. Please post your bug number, just for the record.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

DTS will close for the winter holidays at the end of business on Wed, 23 Dec 2015 and re-open on Mon, 4 Jan 2016.

Submitted 23979839

Can we use client certficates in background session now or this is still not possible?

Can we use client certficates in background session now or this is still not possible?

No. The bug mentioned above (r. 17277089) has been fixed, meaning

nsurlsessiond
no longer crashes in this case, but client certificate authentication still doesn’t work in background sessions. We’re tracking that via a new bug (r. 17526855).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi eskimo,


I am trying to do mutual authentication in WKWebView but I can not make it work. It loads the web page but I get error 403 Forbidden. It seems that webview doesn't send the certificate.


I am using WKWebView, is there any way of doing mutual authentication with it?

-(void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{


completionHandler(NSURLSessionAuthChallengeUseCredential, credential);

}

I am trying to do mutual authentication in WKWebView but I can not make it work.

Indeed. WKWebView does its networking in a different process, so it suffer from the same limitation of NSURLSession background sessions. We’re tracking this specific problem via yet another bug (r. 18340261) but ultimately these both share the same underlying cause (the inability to move client identity credentials between processes).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Quinn,


This is breaking my heart. 😢


Do you know if background sessions support any kind of asymmetric key authentication?


The reason I ask is that we built our app's networking layer to rely on client certificates for client authentication, and pinned server certificates with a self-signed CA cert for server trust authentication. This gave us client authentication and server authentication based on asymmetric keys, with no dependency on third parties like the builtin certificate authorities. This is a bit unusual but we control the client and the server, so there was no advantage to depending on builtin certificate authorities. In fact, that would only weaken the security (by allowing an adversary to install a new CA cert, for instance) and make our system less flexible (by requiring us to deploy onto a validated domain name).


Over the last three weeks we realized that background sessions do not support non-builtin CAs, and therefore do not support our server authentication. This was sad, and kicked off some significant re-engineering of our backend systems.

And with this message I've now realized that the background sessions also do not support our client authentication mechanism either! Extra sad.

So I'm wondering, do background URL sessions support any authentication mechanism that can replace what we were hoping to use? Or do we need to move all this authentication logic up into our server application logic, and treat HTTPS just as a secure channel with no authentication guarantees?


Alexis


p.s. It is a wee bit frustrating that we didn't find anything in the URL Session Programming Guide that mentioned these limitations.

There’s still no way to handle client certificate authentication challenges in a background session. This hasn’t changed relative to my 12 Apr 2017.

You should be able to handle server trust authentication challenges in a background session. However, I strongly recommend against this, for a bunch of different reasons:

  • For background sessions specifically, the resumes necessary to handle this authentication challenge counter against the resume rate limiter.

    Note This applies to all authentication challenges, not just server trust challenges.

  • You will have to disable App Transport Security, which is likely to cause you grief further down the line.

  • Overriding HTTPS server trust evaluation is tricky to get right and mistakes here expose you to security vulnerabilities.

So I'm wondering, do background URL sessions support any authentication mechanism that can replace what we were hoping to use?

Yes. Most authentication challenges are supported in a background session, including server trust (as I mentioned above) and things like HTTP Digest, but they’re all problematic because of the resume rate limiter. I generally recommend that folks avoid authentication challenges and instead implement a custom authentication scheme. One possible approach works something like this:

  1. Have your app use a foreground session to contact the server to get a transfer token. This runs in a foreground session and thus can use whatever authentication you like. Specifically, you could do a certificate pinning check on the server.

    Note I’m using certificate pinning in the generally accepted sense, that is, doing additional security checks above and beyond the built in RFC 2818 checks.

  2. Have the app apply that transfer token to a custom header in the upload request.

  3. Have your server authenticate the request based on that.

Your server can expire the transfer tokens based on the resource timeout of the NSURLSession (

timeoutIntervalForResource
) (which defaults to 7 days, btw).

If you want to get fancy you could:

  • Tie the transfer token to a specific resource.

  • Have the initial exchange return (in addition to the transfer token) a random symmetric cypher key that is used to encrypt the resource (using an authenticating encryption scheme, of course). That allows you to detect any man-in-the-middle funkiness.

Obviously this requires changes on the server side, but it sounds like that won’t be a problem for you.

p.s. It is a wee bit frustrating that we didn't find anything in the URL Session Programming Guide that mentioned these limitations.

Indeed. You should feel free to file a bug against the docs here.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi again,


Thanks for the reply. This makes me aware of a number of risks we did not appreciate.


Could I just follow up to be sure I understand them right? Specifically, even after we‘ve switched to CA-signed server certificates, you point out two major reasons we should still avoid performing our own server trust challenge evaluation (or indeed handling any authentication challenge) with background sessions:


The first reason is we might be penalized by the iOS resume rate limiter:


For background sessions specifically, the resumes necessary to handle this authentication challenge counter against the resume rate limiter.

Note This applies to all authentication challenges, not just server trust challenges.


My question is, is this an issue even if I'm doing something computationally cheap like checking the certificate's common name? In other words, do you mean that any

URLSessionDelegate
object which implements
urlSession(_ session: didReceive: completionHandler:)
is a handicap for background execution, because simply introducing that method creates distinct network tasks?


You will have to disable App Transport Security, which is likely to cause you grief further down the line.


This second point surprised me in a similar way. Is this the case even if we are implementing server trust only in order to make it more demanding than the ATS requirements? To continue the last example, suppose we configure our server with garden variety CA-signed certs (so it would pass normal ATS requirements) but we additionally require the app to ensure that the cert’s common name is expected. Would this also require disabling ATS (and risking re-engineering it later)?


The transfer token scheme you propose sounds like the best way to go if I'm hearing you right.


What we loved about our old setup is it allowed us to offload all of authentication to inert certificate assets and an nginx proxy, which required zero server-side development or maintenance, while it allowed us to host servers off any address without coordinated DNS setup or CA assets. But I guess it was more clever than practical.

My question is, is this an issue even if I'm doing something computationally cheap like checking the certificate's common name?

Yes. The sticking point here is not the computation done in your authentication challenge handler, but the work required to resume (or relaunch) your app in order to run any code.

Imagine you have an app that’s suspended in the background and it receives a silent push notification that tells it to download new content (this is a common scenario for magazine apps, amongst many others). In response it starts N download tasks in a background session. In the absence of a custom authentication challenge handler, the system will happily work away downloading all of those resources and, when they’re all done, resume the app in the background to process the completion handlers. N downloads, 1 resume.

If you introduce an authentication challenge handler the story is not nearly as nice. Before starting a download the system has to resume your app to run your authentication challenge handler. So, for N downloads you need N+1 resumes.

Such resumes are budgeted. Before it resumes your app, the system must allocate the budget for that work. That’s fine for a while but eventually the budget starts to get tight and the system must delay starting your download simply because it doesn’t have the budget to run your authentication challenge handler.

Moreover, the ‘cost’ of resume X+1 is double that of resume X. So each time you resume it gets progressively harder to resume again.

On 23 Oct you wrote:

Over the last three weeks we realized that background sessions do not support non-builtin CAs, and therefore do not support our server authentication.

On 24 Oct I wrote:

You should be able to handle server trust authentication challenges in a background session. However, I strongly recommend against this, for a bunch of different reasons:

You will have to disable App Transport Security, which is likely to cause you grief further down the line.

On 29 Oct you wrote:

This second point surprised me in a similar way. Is this the case even if we are implementing server trust only in order to make it more demanding than the ATS requirements?

No. If you look at the wider context of my quote you’ll see it was related to custom CAs rather than system-trusted CAs. If the server has a certificate issued by a system-trusted CA, you don’t need to disable ATS to access the server. If you want to use an authentication challenge handler to tighten security, that’s fine (modulo the resume rate limiter issues discussed earlier).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Just wondering if the issues regarding client authentication and pinning with background sessions still exist in iOS 12? I was going to implement both in my app, but since it needs to use background sessions it looks like I should hold off unless the situation has changed with iOS 12.


Thank you!


John

Hi eskimo,


Are client certificate authentication challenges in a background session still not supported as of iOS 13.3.1?


My background session delegate's urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge....) method and associated completion handler are being called but I'm seeing the following in the logs.

CredStore - copyIdentPrefs - Error copying Identity cred.  Error=-25300, query={
    class = idnt;
    labl = "[REDACTED]";
    "r_Ref" = 1;
}


If I attempt the same upload on a non-background session with the same callbacks triggered, everything runs fine.


Thank you.

Are client certificate authentication challenges in a background session still not supported as of iOS 13.3.1?

Sadly, that’s still the case. This was fixed for a

WKWebView
a while back, but
NSURLSession
background sessions still suffer from this limitation (r. 17526855).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Are client certificate authentication challenges in a background NSURLSession still not supported … ?

Correct.

Where can see the content of the limitation (r. 17526855)?

That is a Radar bug number and thus there’s no way for you to access it. If you want to be notified of developments here, file your own bug (using Feedback Assistant) and ask that it be dup’d to Radar ID 17526855. Once that happens, your bug will display very limit info about the original bug.

Share and Enjoy

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

Nothing new, I reckon? Given that we're 8 years in with that feature request, I don't hold my breath. Still I duped the radar and am crossing fingers.

Background Transfer Service and Client Certificates
 
 
Q