Problem solved.
A (known) issue with the WebView component was the culprit.
Opened up a DTS support ticket with Apple and got a workaround.
EDIT:
Here's the workaround from DTS ( I have no idea if this is still valid, since it was 3 years ago):
Magnus OK, I've had a chance to look at this and I know what's going
on. Before we start talking about WebView, I need to bring you up to
speed on the delegate methods used by NSURLConnection, which is the
underlying API used to actually load data off the 'net.
NSURLConnection started out supporting a single authentication
delegate callback, -connection:didReceiveAuthenticationChallenge:, to
which it passed the various authentication challenges that were
supported at that time (username/password-style challenges). In Mac
OS X 10.6 (and iOS 3.0) NSURLConnection was enhanced to support two
addition types of authentication challenges for TLS connections: o
client identity challenges
(NSURLAuthenticationMethodClientCertificate), giving the delegate the
opportunity to select a client identity for a given TLS connection o
server trust challenges (NSURLAuthenticationMethodServerTrust), giving
the delegate the opportunity to override the server trust evaluation
for a given TLS connection For compatibility reasons it was not
possible to pass these challenges to the delegate under all
circumstances, so NSURLConnection introduced a new delegate callback,
-connection:canAuthenticateAgainstProtectionSpace:, that allows the delegate to opt in to these challenges.
* * * Now, let's bring this back to your app. As I mentioned, WebView uses
NSURLConnection and, for each connection, acts as the connection
delegate. It intercepts authentication challenges and passes them to
its resource load delegate. This works just fine for old school
authentication challenges, because WebView gets the challenge without
having to do anything special; but it fails for TLS connection
authentication challenges, because the delegate has to opt in those
challenges. What you really need is the WebView version of the
'canAuthenticateAgainstProtectionSpace' authentication challenge.
Well, it turns out that this is actually implemented. In looking
through the open source for WebView, I found that there's a private
delegate callback,
-webView:resource:canAuthenticateAgainstProtectionSpace:forDataSource:,
that does exactly what you want.
http://www.opensource.apple.com/source/WebKit/WebKit-7533.20.25/mac/WebView/WebResourceLoadDelegatePrivate.h
If you implement that method you can opt in to the client identity
authentication challenge and, based on that challenge, present a user
interface that allows the user to select an identity. I prototyped
this in your test app and it works a charm. Here's the code I used to
get the client identity challenge:
- (BOOL)webView:(WebView *)sender resource:(id)identifier canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace
*)protectionSpace forDataSource:(WebDataSource *)dataSource {
NSLog(@"%@", [protectionSpace authenticationMethod]);
return [[protectionSpace authenticationMethod] isEqual:NSURLAuthenticationMethodClientCertificate]; } and here's the
code I used to respond to it:
- (void)webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge
*)challenge fromDataSource:(WebDataSource *)dataSource {
NSLog(@"didReceiveAuthenticationChallenge");
NSString *authenticationMethod = [[challenge protectionSpace] authenticationMethod];
NSLog(@" authenticationMethod = %@", authenticationMethod);
[[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; }
Obviously in a real app you'd need to display some UI and then, once
the user has selected a client identity, create a credential for it
(+[NSURLCredential credentialWithIdentity:certificates:persistence:])
and then apply that credential to the chalenge
(-useCredential:forAuthenticationChallenge:).
* * * So where do you proceed from here? Regardless of what else you do, you should
file a bug against WebView to get the
-webView:resource:canAuthenticateAgainstProtectionSpace:forDataSource: delegate callback published in the public headers. It's an obvious,
and most annoying, omission. http://developer.apple.com/bugreporter/
Once you've filed a bug, please send me the bug number so that I can
associate it with this incident. Beyond that, the way forward is less
clear. If you're creating a non-Mac App Store app, my recommendation
would be that you just implement the
'canAuthenticateAgainstProtectionSpace' delegate callback as I've
shown above and move on with your life. OTOH, if you're creating a
Mac App Store app, where the use of private API, including delegate
callbacks, is strictly prohibited, life gets a lot trickier. Let me
know in that case and we can discuss your options. Share and Enjoy