Skip to content

Regression: NSUrlSessionHandler.ServerCertificateCustomValidationCallback behavior change #116067

Open
@dotMorten

Description

@dotMorten

Apple platform

iOS

Framework version

net9.0-*

Affected platform version

9.0.300

Description

The ServerCertificateCustomValidationCallback has started returning a new value for SslPolicyErrors for the test code provided below.

Steps to Reproduce

Repro method. This used to pass and match behavior of HttpClientHandler and SocketsHttpHandler.

        [TestMethod]
        public async Task RemoteCertificate_ForceFailure()
        {
            // Verifies that the default certificate validator is called for a normal request, and that it can be forced to fail
            int calls = 0;
            Exception callbackAssertFail = null;

#if __IOS__
            var handler = new NSUrlSessionHandler();
            handler.ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
#else
            var handler = new System.Net.Http.SocketsHttpHandler();
            handler.SslOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
#endif
            {
                Interlocked.Increment(ref calls);
                try
                {
                    Assert.AreEqual(SslPolicyErrors.None, sslPolicyErrors, "sslPolicyErrors"); // Fails on iOS since 9.0.300. Now returns `RemoteCertificateChainErrors`
                }
                catch (Exception ex)
                {
                    callbackAssertFail = ex;
                }
                return false;
            };

            var client = new HttpClient(handler);
            // Disable keep-alive and cache to force reconnection for each request
            client.DefaultRequestHeaders.ConnectionClose = true;
            client.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue { NoCache = true, NoStore = true };

            var responseTask = client.GetAsync(new Uri("https://sha256.badssl.com/")); // valid certificate
            try { await responseTask; }
            catch (HttpRequestException) { /* expected */ }
            
            // Expect our validator to be called once
            Assert.AreEqual(1, calls, "numCalls");
            if (callbackAssertFail != null)
            {
                throw callbackAssertFail;
            }
        }

Did you find any workaround?

No

Relevant logs

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions