NSUrlSession:挑战NSURLAuthenticationMethodServerTrust仅在需要客户端证书时失败

时间:2018-04-20 12:54:55

标签: ssl xamarin.ios nsurlsession nsurlsessiondatatask

我们希望将我们的应用程序连接到IIS Web服务。我们使用自签名证书和客户端证书进行身份验证。

当webservice不需要客户端证书身份验证时,一切正常,NSURLAuthenticationMethodServerTrust被调用并且请求继续。 但是当我在我们的服务器上激活客户端证书身份验证时,在使用NSURLAuthenticationMethodServerTrust作为挑战的DidReceiveChallenge之后,会调用DidCompleteWithError。错误消息是:“此服务器的证书无效。您可能正在连接到假装为”192.168.221.118“的服务器,这可能会使您的机密信息面临风险。

注意:永远不会调用“NSURLAuthenticationMethodClientCertificate”,应用程序在此之前崩溃。 客户端证书由中间证书签名,因此我不明白为什么ServerTrust Challenge失败。

另外:在我看来,它没有必要,但我也尝试将客户端证书添加到Sectrust的AnchorCertificates集合中。

提前感谢您的帮助。

这是我的代码:

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

1 个答案:

答案 0 :(得分: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;
                    }