Search code examples
iosweb-servicessslssl-certificatensurlconnection

Accessing installed profiles / certificates from within the app


I'll start off with some background information about our app:

Our iOS app connects to webservices, which in most cases (except from a few whitelisted IP's) require authentication. Because this system is supposed to be incredibly secure, the company opted to use client certificates to allow access to the server. Every user will get a certificate generated based on whether they will use the app or the web interface, which they'll have to download and install themselves.

The system that was in place within the app was as such; the user would try to connect to the webservices. The initial base 'internal' url would fail as they have no access to it, so the base url would change to the url needing the certificate. When the user has no certificate installed, there is a process in place that would allow the user to download his certificate based on a QR code they've received. The certificate would then be installed within the app, and the user can freely access the webservices and use the app.

This system works, but it requires a lot of actions.

Now to the present:

We want to make things easier on the users and the companies using the app want to have a bit more control. Basically, a system is being worked out that will allow companies to create their own certificates, and they want to distribute it using some managing tools. Without going too far into the details, the situation will be that the required certificate will be installed to iOS itself, and not within the app.

And that's where the issue occurs, I can't seem to access the installed certificate from within the app, and keep getting the 401 errors.

I've done a bit of research to start it off, and my initial response was "This will not work" as is said on this page of the official developer page:

In iOS, an app can access only its own items in the keychain—the user is never asked for permission or for a password.

But because we want to be 100% sure, I've continued looking for a while and eventually ran into code examples like:

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
{
    SecTrustRef trust = challenge.protectionSpace.serverTrust;
    NSURLCredential *credential = [NSURLCredential credentialForTrust:trust];
    [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
}

But this doesn't seem to get any installed certificate or anything.

The following booleans are also set:

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace;
{
    return YES;
}

- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection;
{
    return YES;
}

To do some further checking outside of the app itself, I've looked at the iPad we have here. It has a certificate installed for the website (different rights than the one for the app), and on Safari I can access the certificate-protected website. However, on Chrome and Firefox I will error out that the website requires a certificate. So this leads me to believe it's indeed impossible to access these certificates unless you are basically an Apple app.

So basically, I'm at my wits end with this issue. The short version of this question: Can I access the installed client certificate on the iPhone from within my app to access webservices which require this certificate?

And if yes, the long version: How?


Solution

  • If I were you, I would use Managed App Configuration to push a set of custom prefs to the app, and use that to provide a URL where a client cert can be downloaded. Delete it on the server after the first request.