【问题标题】:NSUrlSession: Challenge NSURLAuthenticationMethodServerTrust fails only when client certificate is also neededNSUrlSession:挑战 NSURLAuthenticationMethodServerTrust 仅在还需要客户端证书时才会失败
【发布时间】:2018-04-20 12:54:55
【问题描述】:

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

当 web 服务不需要客户端证书身份验证时,一切正常,调用 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);
                }
            }
}

【问题讨论】:

  • 我想也许你应该用 NSUrlSessionDelegate 做一些工作。参考here
  • 在您的链接中,用户未使用客户端身份验证,而仅使用自签名证书。这已经适用于我已经发布的 NSUrlSessionDelegate 的实现。我的问题是,这仅在服务器还请求客户端证书进行身份验证时才起作用。
  • 也许this link 可以提供帮助。

标签: ssl xamarin.ios nsurlsession nsurlsessiondatatask


【解决方案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;
                    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-11
    • 1970-01-01
    • 2012-10-01
    • 2022-01-17
    相关资源
    最近更新 更多