NSUrlSession: вызов NSURLAuthenticationMethodServerTrust завершается с ошибкой только тогда, когда также требуется сертификат клиента

мы хотим подключить наше приложение к нашему веб-сервису IIS. Мы используем самозаверяющие сертификаты, а также клиентский сертификат для аутентификации.

Когда веб-сервис не требует проверки подлинности клиентского сертификата, все работает нормально, вызывается NSURLAuthenticationMethodServerTrust, и запрос продолжается. Но когда я активирую аутентификацию клиентского сертификата на нашем сервере, после DidReceiveChallenge с NSURLAuthenticationMethodServerTrust в качестве вызова вызывается DidCompleteWithError. Сообщение об ошибке: «Сертификат для этого сервера недействителен. Возможно, вы подключаетесь к серверу, выдающему себя за «192.168.221.118», что может подвергнуть риску вашу конфиденциальную информацию.

Примечание. «NSURLAuthenticationMethodClientCertificate» никогда не вызывается, перед этим происходит сбой приложения. Сертификат клиента подписан промежуточным сертификатом, поэтому я не понимаю, почему не удается выполнить вызов ServerTrust.

Кроме того: на мой взгляд, в этом нет необходимости, но я также попытался добавить сертификат клиента в коллекцию AnchorCertificates Sectrust.

Заранее спасибо за вашу помощь.

Вот мой код:

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);
                }
            }
}

person Tobe    schedule 20.04.2018    source источник
comment
Я думаю, возможно, вам следует немного поработать с NSUrlSessionDelegate. См. здесь.   -  person ColeX - MSFT    schedule 23.04.2018
comment
В вашей ссылке пользователь не использует аутентификацию клиента, а только самозаверяющие сертификаты. Это уже работает с моей реализацией NSUrlSessionDelegate, которую я уже опубликовал. Моя проблема в том, что это ТОЛЬКО не работает, когда сервер также запрашивает сертификат клиента для аутентификации.   -  person Tobe    schedule 24.04.2018
comment
Возможно, поможет эта ссылка.   -  person ColeX - MSFT    schedule 25.04.2018


Ответы (1)


Я наконец нашел решение. Мне пришлось создать объект учетных данных по-другому. Вместо добавления сертификатов в SecTrust и создания учетных данных с SecTrust в качестве параметра мне пришлось создать удостоверение из сертификата клиента, а затем создать учетные данные с удостоверением и другими сертификатами в качестве параметров:

 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;
                    }
person Tobe    schedule 07.05.2018