diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509ChainPolicy.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509ChainPolicy.cs
index 3579b2d1e40c3..0fcb9a2d1fa31 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509ChainPolicy.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509ChainPolicy.cs
@@ -150,7 +150,7 @@ public X509ChainPolicy Clone()
if (_applicationPolicy?.Count > 0)
{
- foreach (var item in _applicationPolicy)
+ foreach (Oid item in _applicationPolicy)
{
clone.ApplicationPolicy.Add(item);
}
@@ -158,7 +158,7 @@ public X509ChainPolicy Clone()
if (_certificatePolicy?.Count > 0)
{
- foreach (var item in _certificatePolicy)
+ foreach (Oid item in _certificatePolicy)
{
clone.CertificatePolicy.Add(item);
}
diff --git a/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj b/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj
index 6ae31358b0242..8334efeb1621d 100644
--- a/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj
+++ b/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj
@@ -284,6 +284,7 @@
+
diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainPolicyTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainPolicyTests.cs
new file mode 100644
index 0000000000000..38f8f40cc3b39
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainPolicyTests.cs
@@ -0,0 +1,148 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.X509Certificates.Tests
+{
+ [SkipOnPlatform(TestPlatforms.Browser, "No X.509 support on browser")]
+ public static class ChainPolicyTests
+ {
+ private static readonly Oid s_emailProtectionEku = new Oid("1.3.6.1.5.5.7.3.4", null);
+ private static readonly Oid s_timestampEku = new Oid("1.3.6.1.5.5.7.3.8", null);
+
+ [Fact]
+ public static void DefaultCtorState()
+ {
+ X509ChainPolicy policy = new X509ChainPolicy();
+ AssertDefaultState(policy);
+ }
+
+ [Fact]
+ public static void ResetAfterChanges()
+ {
+ using (X509Certificate2 cert = new X509Certificate2(SelfSigned1PemBytes))
+ {
+ X509ChainPolicy policy = new X509ChainPolicy();
+ policy.CertificatePolicy.Add(s_emailProtectionEku);
+ policy.ApplicationPolicy.Add(s_timestampEku);
+ policy.ExtraStore.Add(cert);
+ policy.CustomTrustStore.Add(cert);
+ policy.DisableCertificateDownloads = true;
+ policy.VerificationTime = DateTime.MinValue;
+ policy.VerificationTimeIgnored = false;
+ policy.UrlRetrievalTimeout = TimeSpan.MaxValue;
+ policy.VerificationFlags = X509VerificationFlags.IgnoreCtlNotTimeValid;
+ policy.RevocationMode = X509RevocationMode.Offline;
+ policy.RevocationFlag = X509RevocationFlag.EntireChain;
+
+ policy.Reset();
+ AssertDefaultState(policy);
+ }
+ }
+
+ [Fact]
+ public static void SetVerificationTimeClearsIgnored()
+ {
+ X509ChainPolicy policy = new X509ChainPolicy();
+ Assert.True(policy.VerificationTimeIgnored, "policy.VerificationTimeIgnored (Before)");
+ policy.VerificationTime = DateTime.MinValue;
+ Assert.False(policy.VerificationTimeIgnored, "policy.VerificationTimeIgnored (After)");
+ }
+
+ [Fact]
+ public static void VerifyCloneBehavior()
+ {
+ using (X509Certificate2 cert = new X509Certificate2(SelfSigned1PemBytes))
+ using (X509Certificate2 cert2 = new X509Certificate2(SelfSigned1PemBytes))
+ {
+ X509ChainPolicy source = new X509ChainPolicy();
+ source.CertificatePolicy.Add(s_timestampEku);
+ source.ApplicationPolicy.Add(s_emailProtectionEku);
+ source.ExtraStore.Add(cert);
+ source.CustomTrustStore.Add(cert2);
+ source.DisableCertificateDownloads = true;
+ source.VerificationTime = DateTime.MinValue;
+ source.VerificationTimeIgnored = false;
+ source.UrlRetrievalTimeout = TimeSpan.MaxValue;
+ source.VerificationFlags = X509VerificationFlags.IgnoreCtlNotTimeValid;
+ source.RevocationMode = X509RevocationMode.Offline;
+ source.RevocationFlag = X509RevocationFlag.EntireChain;
+
+ X509ChainPolicy clone = source.Clone();
+ Assert.Equal(source.VerificationTime, clone.VerificationTime);
+ Assert.Equal(source.VerificationTimeIgnored, clone.VerificationTimeIgnored);
+ Assert.Equal(source.VerificationFlags, clone.VerificationFlags);
+ Assert.Equal(source.RevocationFlag, clone.RevocationFlag);
+ Assert.Equal(source.RevocationMode, clone.RevocationMode);
+ Assert.Equal(source.UrlRetrievalTimeout, clone.UrlRetrievalTimeout);
+ Assert.Equal(source.DisableCertificateDownloads, clone.DisableCertificateDownloads);
+
+ Assert.NotSame(source.CertificatePolicy, clone.CertificatePolicy);
+ Assert.Equal(source.CertificatePolicy, clone.CertificatePolicy);
+ Assert.Same(source.CertificatePolicy[0], clone.CertificatePolicy[0]);
+
+ Assert.NotSame(source.ApplicationPolicy, clone.ApplicationPolicy);
+ Assert.Equal(source.ApplicationPolicy, clone.ApplicationPolicy);
+ Assert.Same(source.ApplicationPolicy[0], clone.ApplicationPolicy[0]);
+
+ Assert.NotSame(source.ExtraStore, clone.ExtraStore);
+ Assert.Equal(source.ExtraStore, clone.ExtraStore);
+ Assert.Same(source.ExtraStore[0], clone.ExtraStore[0]);
+
+ Assert.NotSame(source.CustomTrustStore, clone.CustomTrustStore);
+ Assert.Equal(source.CustomTrustStore, clone.CustomTrustStore);
+ Assert.Same(source.CustomTrustStore[0], clone.CustomTrustStore[0]);
+
+ Assert.NotSame(source.ExtraStore[0], clone.CustomTrustStore[0]);
+ }
+ }
+
+ private static void AssertDefaultState(X509ChainPolicy policy)
+ {
+ Assert.Equal(X509RevocationFlag.ExcludeRoot, policy.RevocationFlag);
+ Assert.Equal(X509RevocationMode.Online, policy.RevocationMode);
+ Assert.Equal(X509VerificationFlags.NoFlag, policy.VerificationFlags);
+ Assert.Equal(X509ChainTrustMode.System, policy.TrustMode);
+ Assert.False(policy.DisableCertificateDownloads, "policy.DisableCertificateDownloads");
+ Assert.True(policy.VerificationTimeIgnored, "policy.VerificationTimeIgnored");
+ Assert.Equal(TimeSpan.Zero, policy.UrlRetrievalTimeout);
+
+ // A DST adjustment will make the two Now values differ by the jump time, which
+ // is never more than an hour.
+ // An NTP jump is usually limited to 5 minutes.
+ // Add another 10 minutes for never seeing this fail.
+ Assert.Equal(DateTime.Now, policy.VerificationTime, TimeSpan.FromMinutes(75));
+
+ Assert.Empty(policy.ApplicationPolicy);
+ Assert.Empty(policy.CertificatePolicy);
+ Assert.Empty(policy.ExtraStore);
+ Assert.Empty(policy.CustomTrustStore);
+ }
+
+ // TODO (66338): Unify with TestData.SelfSigned1PemBytes after all X509 tests are unified in.
+ private static readonly byte[] SelfSigned1PemBytes = ByteUtils.AsciiBytes(
+ @"-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIJAJpCQ7mtFWHeMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNV
+BAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg
+Q29tcGFueSBMdGQwHhcNMTgwNTMwMTgyNjM1WhcNMTkwNTMwMTgyNjM1WjBCMQsw
+CQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZh
+dWx0IENvbXBhbnkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+pfYZTHjzei9U3QxiIIjESsf9z3Bfl8FAQLIU+OeICN3upnDvTgeWM/Jw7LwiuHhu
+XvSawPwQ8ONvUeSG/wfyjYyTB7VBpVnNi6oTR6E1WSuiu0iT3qlDHVwArTI5DvIM
+FzP3/AT1Ub5SvwVbWiR2za6wuUIsryyLz5+zCwGr+J/Xbmta/H9IT9NLwmDJCZQe
+4Q4hCWhf7FKdXWt59y9PofVnE7R8CKNfUKr6GA+gy+SEtM/cHgqox5PErnV9b14U
+uVROnRUyo1bFwTOdoW3zf5S4VZ4pFPJHNYACHEMiE0eNgfJf+QeyPUPN50neEAbf
+kQYkeEET8dW6JlDFrAI4wwIDAQABo1MwUTAdBgNVHQ4EFgQUK+C/eGYPlV+KaTvj
+tF6lJaKmo3EwHwYDVR0jBBgwFoAUK+C/eGYPlV+KaTvjtF6lJaKmo3EwDwYDVR0T
+AQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAZUjvDMhGc45TLRHKO5rsyifN
+g7qb3dO5vtD/JWeo+wyMYcBHIANIIxYrkT0dRBQWQerVDBvsAESahM3f0SdszGac
+6y1qxQWxfjxRiCwrEQ7JVZkmspYLbOxaS1T2IZUo3D7VJReyna6r11EKy7i49Toa
+KmrhTLBsHV+MUgPRtupiOOu0fXqfxpXE7XEvi0hyv8PKli+Oww2Zyt1jTTvv2RTA
+eJRqTUNUbWEDesXAOh5CY6Xjfg7Gt6IYQHt0JMw29pXB3TV2uyXuvFNsc725cPbW
+JCuC9TGQRUAUj+LZ43tTrfaZ7g5L80/eRrvlx5MIJSsX8cev8pZYx224WRtk/w==
+-----END CERTIFICATE-----
+");
+ }
+}