1

we want to connect our app to our IIS webservice. We use self signed certificates and also a client certificate for authentication.

When the webservice doesn't require client certificate authentication, everything works fine, NSURLAuthenticationMethodServerTrust gets called and the request continues. But when I activate client certificate authentication on our server, after DidReceiveChallenge with NSURLAuthenticationMethodServerTrust as the challenge, DidCompleteWithError gets called. Error message is: "The certificate for this server is invalid. You might be connecting to a server that is pretending to be "192.168.221.118" which could put your confidential information at risk.

Note: "NSURLAuthenticationMethodClientCertificate" never gets called, the app crashes before that. The client certificate is signed by the intermediate certificate, so I don't understand why the ServerTrust Challenge fails.

Also: in my opinion it should not be necessary, but I also tried adding the client certificate to the collection of AnchorCertificates of the Sectrust.

Thanks in advance for your help.

Here is my code:

private class SessionDelegate : NSUrlSessionDataDelegate, INSUrlSessionDelegate
        {
            private Action<bool, string> completed_callback;
            private string antwortCache;
            private int status_code;

            public SessionDelegate(Action<bool, string> completed)
            {
                completed_callback = completed;
                antwortCache = "";
            }
public override void DidReceiveChallenge(NSUrlSession session, NSUrlSessionTask task, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
            {
                if (challenge.PreviousFailureCount == 0)
                {
                    if (challenge.ProtectionSpace.AuthenticationMethod.Equals("NSURLAuthenticationMethodServerTrust"))
                    {
// GetParent is correct, because I'm too lazy to copy the certs into to the correct folders...

                        var path = Directory.GetParent(GlobaleObjekte.SSLZertifikatePath);
                        var caPath = Path.Combine(path.FullName, "ca.cert.der");
                        var caByteArray = File.ReadAllBytes(caPath);
                        var caCert = new X509Certificate2(caByteArray);

                        var interPath = Path.Combine(path.FullName, "intermediate.cert.der");
                        var interByteArray = File.ReadAllBytes(interPath);
                        var interCert = new X509Certificate2(interByteArray);

                        var secTrust = challenge.ProtectionSpace.ServerSecTrust;

                        var certCollection = new X509CertificateCollection();
                        certCollection.Add(caCert);
                        certCollection.Add(interCert);

                        secTrust.SetAnchorCertificates(certCollection);
                        var credential = new NSUrlCredential(secTrust);
                        completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, credential);

                        return;
                    }

                    if (challenge.ProtectionSpace.AuthenticationMethod.Equals("NSURLAuthenticationMethodClientCertificate"))
                    {
                        var path = Directory.GetParent(GlobaleObjekte.SSLZertifikatePath);
                        var certPath = Path.Combine(path.FullName, "client.pfx");
                        var certByteArray = File.ReadAllBytes(certPath);
                        var cert = new X509Certificate2(certByteArray, Settings.WSClientCertPasswort);

                        var ident = SecIdentity.Import(certByteArray, Settings.WSClientCertPasswort);
                        var credential = new NSUrlCredential(ident, new SecCertificate[] { new SecCertificate(cert) }, NSUrlCredentialPersistence.ForSession); 
                       completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, credential);
                        return;
                    }

                    if (challenge.ProtectionSpace.AuthenticationMethod.Equals("NSURLAuthenticationMethodHTTPBasic"))
                    {
                        var credential = new NSUrlCredential(Settings.WebserviceBenutzer, Settings.WebservicePasswort, NSUrlCredentialPersistence.ForSession);
         completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, credential);
                        return;
                    }

                    completed_callback(false, "Unbekannte Authentifizierungsanfrage: " + challenge?.ProtectionSpace?.AuthenticationMethod);
                }
                else
                {
                    completed_callback(false, "Authentifizierung fehlgeschlagen: " + challenge?.ProtectionSpace?.AuthenticationMethod);
                }
            }
}
Tobe
  • 198
  • 2
  • 13
  • I think maybe you should do some work with NSUrlSessionDelegate . Refer to [here](https://stackoverflow.com/a/42953488/8187800). – ColeX Apr 23 '18 at 08:56
  • In your link the user is not using client authentication, but only self signed certificates. This already works with my implementation of NSUrlSessionDelegate, wich I already posted. My problem is that this ONLY does't work when the server also requests a client certificate for authentication. – Tobe Apr 24 '18 at 09:28
  • Maybe [this link](https://stackoverflow.com/questions/41690302/certificate-for-this-server-is-invalid) can help. – ColeX Apr 25 '18 at 09:09

1 Answers1

1

I finally found a solution. I had to create the credential object in a different way. Instead of adding the certificates to the SecTrust and create the credential with the SecTrust as a parameter, I had to create a identity from the client certificate and then create the credential with the identity and the other certificates as parameters:

 if (challenge.ProtectionSpace.AuthenticationMethod.Equals("NSURLAuthenticationMethodServerTrust"))
                    {
                        var path = Directory.GetParent(GlobaleObjekte.SSLZertifikatePath);
                        var caPath = Path.Combine(path.FullName, "ca.cert.der");
                        var caByteArray = File.ReadAllBytes(caPath);
                        var caCert = new SecCertificate(caByteArray);

                        var interPath = Path.Combine(path.FullName, "intermediate.cert.der");
                        var interByteArray = File.ReadAllBytes(interPath);
                        var interCert = new SecCertificate(interByteArray);

                        var clientPath = Path.Combine(path.FullName, "client.pfx");
                        var clientByteArray = File.ReadAllBytes(clientPath);
                        var clientCert = new X509Certificate2(clientByteArray, Settings.WSClientCertPasswort);

                        //var secTrust = challenge.ProtectionSpace.ServerSecTrust;
                        //var certCollection = new X509CertificateCollection();
                        //certCollection.Add(caCert);
                        //certCollection.Add(interCert);
                        //certCollection.Add(cert);

                        //secTrust.SetAnchorCertificates(certCollection);
                        //var credential = new NSUrlCredential(secTrust);
                        var identity = SecIdentity.Import(clientCert);
                        var credential = new NSUrlCredential(identity, new SecCertificate[] { caCert, interCert }, NSUrlCredentialPersistence.ForSession);

                        completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, credential);

                        return;
                    }
Tobe
  • 198
  • 2
  • 13