return -6;
}
- CFIndex count = SecTrustGetCertificateCount(existingTrust);
+ CFIndex certificateCount = SecTrustGetCertificateCount(existingTrust);
- for (CFIndex i = 0; i < count; i++)
+ for (CFIndex i = 0; i < certificateCount; i++)
{
SecCertificateRef item = SecTrustGetCertificateAtIndex(existingTrust, i);
CFArrayAppendValue(certs, item);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
osStatus = SecTrustEvaluate(trust, &trustResult);
+
+ if (trustResult == kSecTrustResultRecoverableTrustFailure && osStatus == noErr && certificateCount > 1)
+ {
+ // If we get recoverable failure, let's try it again with full anchor list.
+ // We already stored just the first certificate into anchors; now we store the rest.
+ for (CFIndex i = 1; i < certificateCount; i++)
+ {
+ CFArrayAppendValue(anchors, SecTrustGetCertificateAtIndex(existingTrust, i));
+ }
+
+ osStatus = SecTrustSetAnchorCertificates(trust, anchors);
+ if (osStatus == noErr)
+ {
+ memset(&trustResult, 0, sizeof(SecTrustResultType));
+ osStatus = SecTrustEvaluate(trust, &trustResult);
+ }
+ }
#pragma clang diagnostic pop
if (osStatus == noErr && trustResult != kSecTrustResultUnspecified && trustResult != kSecTrustResultProceed)
using System.Net.Test.Common;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
-
+using Microsoft.DotNet.XUnitExtensions;
using Xunit;
namespace System.Net.Security.Tests
}
}
+ // MacOS has has special validation rules for apple.com and icloud.com
+ [ConditionalTheory]
+ [OuterLoop("Uses external servers")]
+ [InlineData("www.apple.com")]
+ [InlineData("www.icloud.com")]
+ [PlatformSpecific(TestPlatforms.OSX)]
+ public async Task CertificateValidationApple_EndToEnd_Ok(string host)
+ {
+ using (var client = new TcpClient())
+ {
+ try
+ {
+ await client.ConnectAsync(host, 443);
+ }
+ catch (Exception ex)
+ {
+ // if we cannot connect skip the test instead of failing.
+ new SkipTestException($"Unable to connect to '{host}': {ex.Message}");
+ }
+
+
+ using (SslStream sslStream = new SslStream(client.GetStream(), false, RemoteHttpsCertValidation, null))
+ {
+ await sslStream.AuthenticateAsClientAsync(host);
+ }
+ }
+ }
+
private bool RemoteHttpsCertValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
Assert.Equal(SslPolicyErrors.None, sslPolicyErrors);