diff --git a/UnitTests/Cryptography/SecureMimeTests.cs b/UnitTests/Cryptography/SecureMimeTests.cs index eef1ea46d7..1c60688606 100644 --- a/UnitTests/Cryptography/SecureMimeTests.cs +++ b/UnitTests/Cryptography/SecureMimeTests.cs @@ -78,6 +78,10 @@ public abstract class SecureMimeTestsBase public const string MimeKitFingerprint = "ba4403cd3d876ae8cd261575820330086cc3cbc8"; public const string ThunderbirdName = "fejj@gnome.org"; + public static readonly string[] RelativeConfigFilePaths = { + "certificate-authority.cfg", "intermediate1.cfg", "intermediate2.cfg", "dnsnames/smime.cfg", "dsa/smime.cfg", "ec/smime.cfg", "revoked/smime.cfg", "rsa/smime.cfg" + }; + public static readonly string[] StartComCertificates = { "StartComCertificationAuthority.crt", "StartComClass1PrimaryIntermediateClientCA.crt" }; @@ -102,9 +106,6 @@ public abstract class SecureMimeTestsBase public static readonly X509Crl[] CurrentCrls; public static readonly Uri[] CrlRequestUris; - public static readonly Mock MockHttpMessageHandler; - public static readonly HttpClient MockHttpClient; - protected virtual bool IsEnabled { get { return true; } } protected virtual bool CheckCertificateRevocation { get { return true; } } @@ -122,6 +123,8 @@ protected virtual bool Supports (PublicKeyAlgorithm algorithm) protected abstract SecureMimeContext CreateContext (); + protected abstract Mock GetMockHttpMessageHandler (SecureMimeContext ctx); + static SecureMimeTestsBase () { var dataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "smime"); @@ -130,7 +133,8 @@ static SecureMimeTestsBase () var all = new List (); AsymmetricKeyParameter privateKey; - foreach (var cfg in Directory.GetFiles (dataDir, "*.cfg", SearchOption.AllDirectories)) { + foreach (var relativePath in RelativeConfigFilePaths) { + var cfg = Path.Combine (dataDir, relativePath.Replace ('/', Path.DirectorySeparatorChar)); var name = Path.GetFileNameWithoutExtension (cfg); var pfx = Path.ChangeExtension (cfg, ".pfx"); X509Certificate[] chain; @@ -153,7 +157,7 @@ static SecureMimeTestsBase () break; } - if (smime.EmailAddress.Equals ("revoked@example.com", StringComparison.OrdinalIgnoreCase)) { + if (smime.EmailAddress.Equals ("revoked@mimekit.net", StringComparison.OrdinalIgnoreCase)) { RevokedCertificate = smime; } else if (smime.PublicKeyAlgorithm == PublicKeyAlgorithm.RsaGeneral) { if (!string.IsNullOrEmpty (smime.EmailAddress)) @@ -193,7 +197,7 @@ static SecureMimeTestsBase () break; } - if (smime.EmailAddress.Equals ("revoked@example.com", StringComparison.OrdinalIgnoreCase)) { + if (smime.EmailAddress.Equals ("revoked@mimekit.net", StringComparison.OrdinalIgnoreCase)) { RevokedCertificate = smime; } else if (smime.PublicKeyAlgorithm == PublicKeyAlgorithm.RsaGeneral) { if (!string.IsNullOrEmpty (smime.EmailAddress)) @@ -220,7 +224,7 @@ static SecureMimeTestsBase () SMimeCertificates = all.ToArray (); var certificates = SMimeCertificates.Select (cert => cert.Certificate).ToArray (); - var yesterday = DateTime.Now.Subtract (TimeSpan.FromDays (1)); + var yesterday = DateTime.UtcNow.Subtract (TimeSpan.FromDays (1)); var threeMonthsAgo = yesterday.Subtract (TimeSpan.FromDays (90)); var threeMonthsFromNow = yesterday.Add (TimeSpan.FromDays (90)); @@ -241,7 +245,10 @@ static SecureMimeTestsBase () new Uri ("https://mimekit.net/crls/intermediate1.crl"), new Uri ("https://mimekit.net/crls/intermediate2.crl") }; + } + protected static Mock CreateMockHttpMessageHandler () + { var responses = new HttpResponseMessage[] { new HttpResponseMessage (HttpStatusCode.OK) { Content = new ByteArrayContent (CurrentCrls[0].GetEncoded ()) @@ -254,13 +261,13 @@ static SecureMimeTestsBase () } }; - MockHttpMessageHandler = new Mock (MockBehavior.Strict); + var mockHttpMessageHandler = new Mock (MockBehavior.Strict); for (int i = 0; i < CrlRequestUris.Length; i++) { var requestUri = CrlRequestUris[i]; var response = responses[i]; - MockHttpMessageHandler + mockHttpMessageHandler .Protected () .Setup> ( "SendAsync", @@ -269,7 +276,7 @@ static SecureMimeTestsBase () .ReturnsAsync (response); } - MockHttpClient = new HttpClient (MockHttpMessageHandler.Object); + return mockHttpMessageHandler; } protected void ImportTestCertificates (SecureMimeContext ctx) @@ -350,8 +357,12 @@ protected SecureMimeTestsBase () if (!IsEnabled) return; - using (var ctx = CreateContext ()) + using (var ctx = CreateContext ()) { ImportTestCertificates (ctx); + + foreach (var crl in ObsoleteCrls) + ctx.Import (crl); + } } public static X509Certificate LoadCertificate (string path) @@ -2841,16 +2852,31 @@ public async Task TestSecureMimeVerifyMixedLineEndingsAsync () } } - void AssertCrlsRequested () + void AssertCrlsRequested (SecureMimeContext ctx) { - for (int i = 0; i < CrlRequestUris.Length; i++) { - var requestUri = CrlRequestUris[i]; + var mockHttpMessageHandler = GetMockHttpMessageHandler (ctx); + Times times; + + // Note: For TemporarySecureMimeContext tests, the ctx gets globally shared so the Mock will will get reused as well + // ... but for other SecureMimeContext implementations, the ctx is not globally shared, so the Mock will not get reused + // which means that if the storage backing already has the latest CRLs, then they won't get re-downloaded. + if (ctx is TemporarySecureMimeContext) + times = Times.Exactly (1); + else + times = Times.AtMostOnce (); + + try { + for (int i = 0; i < CrlRequestUris.Length; i++) { + var requestUri = CrlRequestUris[i]; - MockHttpMessageHandler.Protected ().Verify ( - "SendAsync", - Times.AtLeast (1), - ItExpr.Is (m => m.Method == HttpMethod.Get && m.RequestUri == requestUri), - ItExpr.IsAny ()); + mockHttpMessageHandler.Protected ().Verify ( + "SendAsync", + times, + ItExpr.Is (m => m.Method == HttpMethod.Get && m.RequestUri == requestUri), + ItExpr.IsAny ()); + } + } catch (Exception ex) { + Assert.Fail (ex.Message); } } @@ -2885,7 +2911,7 @@ public void TestVerifyRevokedCertificate () var signatures = multipart.Verify (ctx); Assert.That (signatures.Count, Is.EqualTo (1), "Verify returned an unexpected number of signatures."); - AssertCrlsRequested (); + AssertCrlsRequested (ctx); var signature = signatures[0]; @@ -2970,7 +2996,7 @@ public async Task TestVerifyRevokedCertificateAsync () var signatures = await multipart.VerifyAsync (ctx); Assert.That (signatures.Count, Is.EqualTo (1), "Verify returned an unexpected number of signatures."); - AssertCrlsRequested (); + AssertCrlsRequested (ctx); var signature = signatures[0]; @@ -3030,13 +3056,19 @@ public class SecureMimeTests : SecureMimeTestsBase { class MyTemporarySecureMimeContext : TemporarySecureMimeContext { + public readonly Mock MockHttpMessageHandler; + readonly HttpClient client; + public MyTemporarySecureMimeContext () : base (new SecureRandom (new CryptoApiRandomGenerator ())) { CheckCertificateRevocation = false; + + MockHttpMessageHandler = CreateMockHttpMessageHandler (); + client = new HttpClient (MockHttpMessageHandler.Object); } protected override HttpClient HttpClient { - get { return MockHttpClient; } + get { return client; } } } @@ -3046,6 +3078,11 @@ protected override SecureMimeContext CreateContext () { return ctx; } + + protected override Mock GetMockHttpMessageHandler (SecureMimeContext ctx) + { + return ((MyTemporarySecureMimeContext) ctx).MockHttpMessageHandler; + } } [TestFixture] @@ -3053,13 +3090,19 @@ public class SecureMimeSqliteTests : SecureMimeTestsBase { class MySecureMimeContext : DefaultSecureMimeContext { + public readonly Mock MockHttpMessageHandler; + readonly HttpClient client; + public MySecureMimeContext () : base ("smime.db", "no.secret") { CheckCertificateRevocation = false; + + MockHttpMessageHandler = CreateMockHttpMessageHandler (); + client = new HttpClient (MockHttpMessageHandler.Object); } protected override HttpClient HttpClient { - get { return MockHttpClient; } + get { return client; } } } @@ -3068,6 +3111,11 @@ protected override SecureMimeContext CreateContext () return new MySecureMimeContext (); } + protected override Mock GetMockHttpMessageHandler (SecureMimeContext ctx) + { + return ((MySecureMimeContext) ctx).MockHttpMessageHandler; + } + static SecureMimeSqliteTests () { if (File.Exists ("smime.db")) @@ -3123,6 +3171,11 @@ protected override SecureMimeContext CreateContext () return new WindowsSecureMimeContext (); } + protected override Mock GetMockHttpMessageHandler (SecureMimeContext ctx) + { + return null; + } + protected override EncryptionAlgorithm[] GetEncryptionAlgorithms (IDigitalSignature signature) { return ((WindowsSecureMimeDigitalSignature) signature).EncryptionAlgorithms; diff --git a/UnitTests/TestData/smime/certificate-authority.cfg b/UnitTests/TestData/smime/certificate-authority.cfg index 63c6274eef..42614db3c5 100644 --- a/UnitTests/TestData/smime/certificate-authority.cfg +++ b/UnitTests/TestData/smime/certificate-authority.cfg @@ -7,10 +7,10 @@ FileName = certificate-authority.key CountryName = US StateOrProvinceName = Massachusetts LocalityName = Boston -OrganizationName = Example Authority Inc. +OrganizationName = MimeKit Authority Inc. OrganizationalUnitName = IT -CommonName = Example Certification Authority -EmailAddress = root@example.com +CommonName = MimeKit Root Certification Authority +EmailAddress = root@mimekit.net [Revocation] DistributionPoint = https://mimekit.net/crls/certificate-authority.crl diff --git a/UnitTests/TestData/smime/certificate-authority.pfx b/UnitTests/TestData/smime/certificate-authority.pfx index 70cece0c3d..278a2c38dc 100644 Binary files a/UnitTests/TestData/smime/certificate-authority.pfx and b/UnitTests/TestData/smime/certificate-authority.pfx differ diff --git a/UnitTests/TestData/smime/dnsnames/smime.cfg b/UnitTests/TestData/smime/dnsnames/smime.cfg index f09865ddb8..0627b5033e 100644 --- a/UnitTests/TestData/smime/dnsnames/smime.cfg +++ b/UnitTests/TestData/smime/dnsnames/smime.cfg @@ -13,7 +13,7 @@ CommonName = MimeKit UnitTests DistributionPoint = https://mimekit.net/crls/intermediate2.crl [SubjectAlternativeNames] -DnsName = domain-wide.example.com +DnsName = domain-wide.mimekit.net DnsName = Lothlórien.com [Generator] diff --git a/UnitTests/TestData/smime/dnsnames/smime.pfx b/UnitTests/TestData/smime/dnsnames/smime.pfx index b6107ef671..f38bfdfe36 100644 Binary files a/UnitTests/TestData/smime/dnsnames/smime.pfx and b/UnitTests/TestData/smime/dnsnames/smime.pfx differ diff --git a/UnitTests/TestData/smime/dsa/smime.cfg b/UnitTests/TestData/smime/dsa/smime.cfg index d1e15e42a5..abd4b9baed 100644 --- a/UnitTests/TestData/smime/dsa/smime.cfg +++ b/UnitTests/TestData/smime/dsa/smime.cfg @@ -8,7 +8,7 @@ CountryName = US StateOrProvinceName = Massachusetts LocalityName = Boston CommonName = MimeKit UnitTests -EmailAddress = mimekit@dsa.example.com +EmailAddress = dsa@mimekit.net [Revocation] DistributionPoint = https://mimekit.net/crls/intermediate2.crl diff --git a/UnitTests/TestData/smime/dsa/smime.pfx b/UnitTests/TestData/smime/dsa/smime.pfx index fda8fe1da4..52dcfea340 100644 Binary files a/UnitTests/TestData/smime/dsa/smime.pfx and b/UnitTests/TestData/smime/dsa/smime.pfx differ diff --git a/UnitTests/TestData/smime/ec/smime.cfg b/UnitTests/TestData/smime/ec/smime.cfg index f01b09a855..e3040d9c41 100644 --- a/UnitTests/TestData/smime/ec/smime.cfg +++ b/UnitTests/TestData/smime/ec/smime.cfg @@ -8,7 +8,7 @@ CountryName = US StateOrProvinceName = Massachusetts LocalityName = Boston CommonName = MimeKit UnitTests -EmailAddress = mimekit@ec.example.com +EmailAddress = ec@mimekit.net [Revocation] DistributionPoint = https://mimekit.net/crls/intermediate2.crl diff --git a/UnitTests/TestData/smime/ec/smime.pfx b/UnitTests/TestData/smime/ec/smime.pfx index 46ff887f26..d644f0271b 100644 Binary files a/UnitTests/TestData/smime/ec/smime.pfx and b/UnitTests/TestData/smime/ec/smime.pfx differ diff --git a/UnitTests/TestData/smime/intermediate1.cfg b/UnitTests/TestData/smime/intermediate1.cfg index ac6161a2fa..eee41d54f9 100644 --- a/UnitTests/TestData/smime/intermediate1.cfg +++ b/UnitTests/TestData/smime/intermediate1.cfg @@ -7,9 +7,9 @@ FileName = intermediate1.key CountryName = US StateOrProvinceName = Massachusetts LocalityName = Boston -OrganizationName = Example Authority Inc. +OrganizationName = MimeKit Authority Inc. OrganizationalUnitName = IT -CommonName = Example Primary Intermediate CA +CommonName = MimeKit Primary Intermediate CA [Revocation] DistributionPoint = https://mimekit.net/crls/certificate-authority.crl diff --git a/UnitTests/TestData/smime/intermediate1.pfx b/UnitTests/TestData/smime/intermediate1.pfx index bd2f4e4ca4..ac61b60896 100644 Binary files a/UnitTests/TestData/smime/intermediate1.pfx and b/UnitTests/TestData/smime/intermediate1.pfx differ diff --git a/UnitTests/TestData/smime/intermediate2.cfg b/UnitTests/TestData/smime/intermediate2.cfg index 72612138ed..767b0d79e9 100644 --- a/UnitTests/TestData/smime/intermediate2.cfg +++ b/UnitTests/TestData/smime/intermediate2.cfg @@ -7,9 +7,9 @@ FileName = intermediate2.key CountryName = US StateOrProvinceName = Massachusetts LocalityName = Boston -OrganizationName = Example Authority Inc. +OrganizationName = MimeKit Authority Inc. OrganizationalUnitName = IT -CommonName = Example Secondary Intermediate CA +CommonName = MimeKit Secondary Intermediate CA [Revocation] DistributionPoint = https://mimekit.net/crls/intermediate1.crl diff --git a/UnitTests/TestData/smime/intermediate2.pfx b/UnitTests/TestData/smime/intermediate2.pfx index 86a24aae69..8371d5da92 100644 Binary files a/UnitTests/TestData/smime/intermediate2.pfx and b/UnitTests/TestData/smime/intermediate2.pfx differ diff --git a/UnitTests/TestData/smime/revoked/smime.cfg b/UnitTests/TestData/smime/revoked/smime.cfg index d3c6c84a87..b35fbe8758 100644 --- a/UnitTests/TestData/smime/revoked/smime.cfg +++ b/UnitTests/TestData/smime/revoked/smime.cfg @@ -8,7 +8,7 @@ CountryName = US StateOrProvinceName = Massachusetts LocalityName = Boston CommonName = MimeKit UnitTests -EmailAddress = revoked@example.com +EmailAddress = revoked@mimekit.net [Revocation] DistributionPoint = https://mimekit.net/crls/intermediate2.crl diff --git a/UnitTests/TestData/smime/revoked/smime.pfx b/UnitTests/TestData/smime/revoked/smime.pfx index af466f0fcd..75d3303430 100644 Binary files a/UnitTests/TestData/smime/revoked/smime.pfx and b/UnitTests/TestData/smime/revoked/smime.pfx differ diff --git a/UnitTests/TestData/smime/rsa/smime.cfg b/UnitTests/TestData/smime/rsa/smime.cfg index 7c5fa40835..19f829177d 100644 --- a/UnitTests/TestData/smime/rsa/smime.cfg +++ b/UnitTests/TestData/smime/rsa/smime.cfg @@ -8,7 +8,7 @@ CountryName = US StateOrProvinceName = Massachusetts LocalityName = Boston CommonName = MimeKit UnitTests -EmailAddress = mimekit@example.com +EmailAddress = rsa@mimekit.net [Revocation] DistributionPoint = https://mimekit.net/crls/intermediate2.crl diff --git a/UnitTests/TestData/smime/rsa/smime.pfx b/UnitTests/TestData/smime/rsa/smime.pfx index 919f59ab17..e3fc19b827 100644 Binary files a/UnitTests/TestData/smime/rsa/smime.pfx and b/UnitTests/TestData/smime/rsa/smime.pfx differ