Search code examples
iossslxamarinxamarin.iosclient-certificates

Client Certificate Authentication with Xamarin iOS


I've managed to use client certificates successfully with the .Net HttpWebRequest class but I'm now trying to update ModernHttpClient to support Client Certificates so it's using the more efficient iOS libraries for requests.

I've modified the DidReceiveChallenge function in NSUrlSessionHandler to check for ClientCertificate challenges and attempted to follow through the information on https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/AuthenticationChallenges.html and convert it to work with Xamarin iOS. The code compiles correctly and stepping through it causes no errors to be printed out but ultimately I still get a System.Net.WebException thrown with the message 'The server "xxx.example.com" requires a client certificate'.

My code is below...

public override void DidReceiveChallenge(NSUrlSession session, NSUrlSessionTask task, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
{
    ...snip... 

    if (challenge.ProtectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodClientCertificate)
    {
        Console.WriteLine("Client Cert!");

        var password = "xxxxx";
        var options = NSDictionary.FromObjectAndKey(NSObject.FromObject(password), SecImportExport.Passphrase);

        var path = Path.Combine(NSBundle.MainBundle.BundlePath, "Content", "client.p12");
        var certData = File.ReadAllBytes(path);

        NSDictionary[] importResult;

        X509Certificate cert = new X509Certificate(certData, password);

        SecStatusCode statusCode = SecImportExport.ImportPkcs12(certData, options, out importResult);
        var identityHandle = importResult[0][SecImportExport.Identity];
        var identity = new SecIdentity(identityHandle.ClassHandle);
        var certificate = new SecCertificate(cert.GetRawCertData());

        SecCertificate[] certificates = { certificate };
        NSUrlCredential credential = NSUrlCredential.FromIdentityCertificatesPersistance(identity, certificates, NSUrlCredentialPersistence.ForSession);
        completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, credential);

        return;
    }

    ...snip...
}

I've committed my changes so far to GitHub if you want to trial it out (https://github.com/MrsKensington/ModernHttpClient). BTW, the test client certificate secured web server has absolutely nothing of any value on it (only one .txt file) and the certificate and password is unique to this web server, so I have no qualms with sharing this with the world.

Thanks in advance for any help,

Mrs Kensington


Solution

  • Shouldn't you use the handle instead of the classhandle ?

    var identity = new SecIdentity(identityHandle.Handle);
    

    Have you made any progress so far? I need similar code for a WkWebView app.