From 5729d4ebf2bb2c18d5f658f97fdda0c8473c3e34 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Wed, 13 Apr 2022 17:57:28 -0400 Subject: [PATCH 1/5] Condition S.S.Cryptography tests on SHA1 signature support --- .../RSA/RSAFactory.cs | 3 + .../RSA/RSASignatureFormatter.cs | 4 +- .../RSA/SignVerify.cs | 74 +++++++++++-------- .../RSA/SignVerify.netcoreapp.cs | 2 +- .../tests/RSACngProvider.cs | 2 + .../tests/RSACryptoServiceProviderProvider.cs | 2 + .../tests/RSAOpenSslProvider.cs | 37 ++++++++++ .../tests/DefaultRSAProvider.cs | 36 +++++++++ 8 files changed, 125 insertions(+), 35 deletions(-) diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAFactory.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAFactory.cs index 56d4978f756d6c..9a4b27348ab4a0 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAFactory.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAFactory.cs @@ -11,6 +11,7 @@ public interface IRSAProvider bool SupportsLargeExponent { get; } bool SupportsSha2Oaep { get; } bool SupportsPss { get; } + bool SupportsSha1Signatures { get; } } public static partial class RSAFactory @@ -39,5 +40,7 @@ public static RSA Create(RSAParameters rsaParameters) public static bool SupportsSha2Oaep => s_provider.SupportsSha2Oaep; public static bool SupportsPss => s_provider.SupportsPss; + + public static bool SupportsSha1Signatures => s_provider.SupportsSha1Signatures; } } diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSASignatureFormatter.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSASignatureFormatter.cs index d58ac86a4cbebe..c1ce8e1754b87a 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSASignatureFormatter.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSASignatureFormatter.cs @@ -10,7 +10,7 @@ namespace System.Security.Cryptography.Rsa.Tests [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")] public partial class RSASignatureFormatterTests : AsymmetricSignatureFormatterTests { - [Fact] + [ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))] public static void VerifySignature_SHA1() { using (RSA rsa = RSAFactory.Create()) @@ -66,7 +66,7 @@ public static void InvalidHashAlgorithm() } } - [Fact] + [ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))] public static void VerifyKnownSignature() { byte[] hash = "012d161304fa0c6321221516415813022320620c".HexToByteArray(); diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs index e78cea374bac53..0bbdd7db7372da 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; +using Microsoft.DotNet.XUnitExtensions; using Test.Cryptography; using Test.IO.Streams; using Xunit; @@ -26,14 +27,14 @@ public void NullArray_Throws() { using (RSA rsa = RSAFactory.Create()) { - AssertExtensions.Throws("data", () => SignData(rsa, null, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)); - AssertExtensions.Throws("hash", () => SignHash(rsa, null, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)); + AssertExtensions.Throws("data", () => SignData(rsa, null, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); + AssertExtensions.Throws("hash", () => SignHash(rsa, null, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); - AssertExtensions.Throws("data", () => VerifyData(rsa, null, new byte[1], HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)); - AssertExtensions.Throws("hash", () => VerifyHash(rsa, null, new byte[1], HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)); + AssertExtensions.Throws("data", () => VerifyData(rsa, null, new byte[1], HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); + AssertExtensions.Throws("hash", () => VerifyHash(rsa, null, new byte[1], HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); - AssertExtensions.Throws("signature", () => VerifyData(rsa, new byte[1], null, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)); - AssertExtensions.Throws("signature", () => VerifyHash(rsa, new byte[1], null, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)); + AssertExtensions.Throws("signature", () => VerifyData(rsa, new byte[1], null, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); + AssertExtensions.Throws("signature", () => VerifyHash(rsa, new byte[1], null, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); } } } @@ -72,10 +73,10 @@ public void NullPadding_Throws() { using (RSA rsa = RSAFactory.Create()) { - AssertExtensions.Throws("padding", () => SignData(rsa, new byte[1], HashAlgorithmName.SHA1, null)); - AssertExtensions.Throws("padding", () => SignHash(rsa, new byte[1], HashAlgorithmName.SHA1, null)); - AssertExtensions.Throws("padding", () => VerifyData(rsa, new byte[1], new byte[1], HashAlgorithmName.SHA1, null)); - AssertExtensions.Throws("padding", () => VerifyHash(rsa, new byte[1], new byte[1], HashAlgorithmName.SHA1, null)); + AssertExtensions.Throws("padding", () => SignData(rsa, new byte[1], HashAlgorithmName.SHA256, null)); + AssertExtensions.Throws("padding", () => SignHash(rsa, new byte[1], HashAlgorithmName.SHA256, null)); + AssertExtensions.Throws("padding", () => VerifyData(rsa, new byte[1], new byte[1], HashAlgorithmName.SHA256, null)); + AssertExtensions.Throws("padding", () => VerifyHash(rsa, new byte[1], new byte[1], HashAlgorithmName.SHA256, null)); } } @@ -87,7 +88,7 @@ public void UseAfterDispose(bool importKey) RSA rsa = importKey ? RSAFactory.Create(TestData.RSA2048Params) : RSAFactory.Create(1024); byte[] data = TestData.HelloBytes; byte[] sig; - HashAlgorithmName alg = HashAlgorithmName.SHA1; + HashAlgorithmName alg = HashAlgorithmName.SHA256; RSASignaturePadding padding = RSASignaturePadding.Pkcs1; using (rsa) @@ -115,12 +116,12 @@ public void InvalidKeySize_DoesNotInvalidateKey() { using (RSA rsa = RSAFactory.Create()) { - byte[] signature = SignData(rsa, TestData.HelloBytes, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + byte[] signature = SignData(rsa, TestData.HelloBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); // A 2049-bit key is hard to describe, none of the providers support it. Assert.ThrowsAny(() => rsa.KeySize = 2049); - Assert.True(VerifyData(rsa, TestData.HelloBytes, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)); + Assert.True(VerifyData(rsa, TestData.HelloBytes, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); } } @@ -143,11 +144,11 @@ public void SignEmptyHash() using (RSA rsa = RSAFactory.Create()) { Assert.ThrowsAny( - () => SignHash(rsa, Array.Empty(), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)); + () => SignHash(rsa, Array.Empty(), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); } } - [Fact] + [ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))] public void ExpectedSignature_SHA1_384() { byte[] expectedSignature = @@ -178,7 +179,7 @@ public void ExpectedSignature_SHA1_384() } } - [Fact] + [ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))] public void ExpectedSignature_SHA1_1032() { byte[] expectedSignature = @@ -205,7 +206,7 @@ public void ExpectedSignature_SHA1_1032() ExpectSignature(expectedSignature, TestData.HelloBytes, "SHA1", TestData.RSA1032Parameters); } - [Fact] + [ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))] public void ExpectedSignature_SHA1_2048() { byte[] expectedSignature = new byte[] @@ -350,7 +351,7 @@ public void ExpectSignature_SHA256_1024_Stream() Assert.Equal(expectedSignature, signature); } - [Fact] + [ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))] public void VerifySignature_SHA1_384() { byte[] signature = @@ -366,7 +367,7 @@ public void VerifySignature_SHA1_384() VerifySignature(signature, TestData.HelloBytes, "SHA1", TestData.RSA384Parameters); } - [Fact] + [ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))] public void VerifySignature_SHA1_1032() { byte[] signature = @@ -393,7 +394,7 @@ public void VerifySignature_SHA1_1032() VerifySignature(signature, TestData.HelloBytes, "SHA1", TestData.RSA1032Parameters); } - [Fact] + [ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))] public void VerifySignature_SHA1_2048() { byte[] signature = new byte[] @@ -516,8 +517,12 @@ public static IEnumerable RoundTripTheories { foreach (RSAParameters rsaParameters in new[] { TestData.RSA1024Params, TestData.RSA2048Params }) { + if (RSAFactory.SupportsSha1Signatures) + { + yield return new object[] { nameof(HashAlgorithmName.SHA1), rsaParameters }; + } + yield return new object[] { nameof(HashAlgorithmName.MD5), rsaParameters }; - yield return new object[] { nameof(HashAlgorithmName.SHA1), rsaParameters }; yield return new object[] { nameof(HashAlgorithmName.SHA256), rsaParameters }; } @@ -532,8 +537,8 @@ public void NegativeVerify_WrongAlgorithm() using (RSA rsa = RSAFactory.Create()) { rsa.ImportParameters(TestData.RSA2048Params); - byte[] signature = SignData(rsa, TestData.HelloBytes, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); - bool signatureMatched = VerifyData(rsa, TestData.HelloBytes, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + byte[] signature = SignData(rsa, TestData.HelloBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + bool signatureMatched = VerifyData(rsa, TestData.HelloBytes, signature, HashAlgorithmName.SHA384, RSASignaturePadding.Pkcs1); Assert.False(signatureMatched); } @@ -545,12 +550,12 @@ public void NegativeVerify_WrongSignature() using (RSA rsa = RSAFactory.Create()) { rsa.ImportParameters(TestData.RSA2048Params); - byte[] signature = SignData(rsa, TestData.HelloBytes, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + byte[] signature = SignData(rsa, TestData.HelloBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); // Invalidate the signature. signature[0] = unchecked((byte)~signature[0]); - bool signatureMatched = VerifyData(rsa, TestData.HelloBytes, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + bool signatureMatched = VerifyData(rsa, TestData.HelloBytes, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); Assert.False(signatureMatched); } } @@ -561,8 +566,8 @@ public void NegativeVerify_TamperedData() using (RSA rsa = RSAFactory.Create()) { rsa.ImportParameters(TestData.RSA2048Params); - byte[] signature = SignData(rsa, TestData.HelloBytes, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); - bool signatureMatched = VerifyData(rsa, Array.Empty(), signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + byte[] signature = SignData(rsa, TestData.HelloBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + bool signatureMatched = VerifyData(rsa, Array.Empty(), signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); Assert.False(signatureMatched); } } @@ -575,13 +580,13 @@ public void NegativeVerify_BadKeysize() using (RSA rsa = RSAFactory.Create()) { rsa.ImportParameters(TestData.RSA2048Params); - signature = SignData(rsa, TestData.HelloBytes, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + signature = SignData(rsa, TestData.HelloBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); } using (RSA rsa = RSAFactory.Create()) { rsa.ImportParameters(TestData.RSA1024Params); - bool signatureMatched = VerifyData(rsa, TestData.HelloBytes, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + bool signatureMatched = VerifyData(rsa, TestData.HelloBytes, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); Assert.False(signatureMatched); } @@ -610,7 +615,7 @@ public void PkcsSignHash_MismatchedHashSize() } } - [Fact] + [ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))] public void ExpectedHashSignature_SHA1_2048() { byte[] expectedHashSignature = new byte[] @@ -741,7 +746,7 @@ public void ExpectedHashSignature_SHA256_2048() ExpectHashSignature(expectedHashSignature, dataHash, "SHA256", TestData.RSA2048Params); } - [Fact] + [ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))] public void VerifyHashSignature_SHA1_2048() { byte[] hashSignature = new byte[] @@ -872,7 +877,7 @@ public void VerifyHashSignature_SHA256_2048() VerifyHashSignature(hashSignature, dataHash, "SHA256", TestData.RSA2048Params); } - [Theory] + [ConditionalTheory] [InlineData("SHA256")] [InlineData("SHA384")] [InlineData("SHA512")] @@ -880,6 +885,11 @@ public void VerifyHashSignature_SHA256_2048() [InlineData("SHA1")] public void PssRoundtrip(string hashAlgorithmName) { + if (!RSAFactory.SupportsSha1Signatures && hashAlgorithmName == "SHA1") + { + throw new SkipTestException("Platform does not support RSA with SHA1 signatures."); + } + RSAParameters privateParameters = TestData.RSA2048Params; RSAParameters publicParameters = new RSAParameters { diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.netcoreapp.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.netcoreapp.cs index e79beb71246b95..fcb06908e91620 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.netcoreapp.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.netcoreapp.cs @@ -56,7 +56,7 @@ public static void VerifyDefaultSpanHash() byte[] signature = new byte[2048 / 8]; Assert.False( - rsa.VerifyHash(ReadOnlySpan.Empty, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)); + rsa.VerifyHash(ReadOnlySpan.Empty, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); if (RSAFactory.SupportsPss) { diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngProvider.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngProvider.cs index 76854a55f07b64..963bd925d800c7 100644 --- a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngProvider.cs +++ b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngProvider.cs @@ -34,6 +34,8 @@ public bool Supports384PrivateKey public bool SupportsSha2Oaep => true; public bool SupportsPss => true; + + public bool SupportsSha1Signatures => true; } public partial class RSAFactory diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs b/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs index 763925168a3933..3efd5501121863 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs +++ b/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs @@ -18,6 +18,8 @@ public class RSACryptoServiceProviderProvider : IRSAProvider public bool SupportsSha2Oaep => false; public bool SupportsPss => false; + + public bool SupportsSha1Signatures => true; } public partial class RSAFactory diff --git a/src/libraries/System.Security.Cryptography.OpenSsl/tests/RSAOpenSslProvider.cs b/src/libraries/System.Security.Cryptography.OpenSsl/tests/RSAOpenSslProvider.cs index 8244f389e63cd5..fca69e5a8a4ea2 100644 --- a/src/libraries/System.Security.Cryptography.OpenSsl/tests/RSAOpenSslProvider.cs +++ b/src/libraries/System.Security.Cryptography.OpenSsl/tests/RSAOpenSslProvider.cs @@ -5,6 +5,8 @@ namespace System.Security.Cryptography.Rsa.Tests { public class RSAOpenSslProvider : IRSAProvider { + private bool? _supportsSha1Signatures; + public RSA Create() => new RSAOpenSsl(); public RSA Create(int keySize) => new RSAOpenSsl(keySize); @@ -16,6 +18,41 @@ public class RSAOpenSslProvider : IRSAProvider public bool SupportsSha2Oaep => true; public bool SupportsPss => true; + + public bool SupportsSha1Signatures + { + get + { + if (!_supportsSha1Signatures.HasValue) + { + if (OperatingSystem.IsLinux()) + { + RSA rsa = Create(); + + try + { + rsa.SignData(Array.Empty(), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + _supportsSha1Signatures = true; + } + catch (CryptographicException) + { + _supportsSha1Signatures = false; + } + finally + { + rsa.Dispose(); + } + } + else + { + // Currently all non-Linux OSes support RSA-SHA1. + _supportsSha1Signatures = true; + } + } + + return _supportsSha1Signatures.Value; + } + } } public partial class RSAFactory diff --git a/src/libraries/System.Security.Cryptography/tests/DefaultRSAProvider.cs b/src/libraries/System.Security.Cryptography/tests/DefaultRSAProvider.cs index 36e3efad794ae6..7b9afb86930afa 100644 --- a/src/libraries/System.Security.Cryptography/tests/DefaultRSAProvider.cs +++ b/src/libraries/System.Security.Cryptography/tests/DefaultRSAProvider.cs @@ -8,6 +8,7 @@ namespace System.Security.Cryptography.Rsa.Tests public class DefaultRSAProvider : IRSAProvider { private bool? _supports384PrivateKey; + private bool? _supportsSha1Signatures; public RSA Create() => RSA.Create(); @@ -38,6 +39,41 @@ public bool Supports384PrivateKey } } + public bool SupportsSha1Signatures + { + get + { + if (!_supportsSha1Signatures.HasValue) + { + if (OperatingSystem.IsLinux()) + { + RSA rsa = Create(); + + try + { + rsa.SignData(Array.Empty(), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + _supportsSha1Signatures = true; + } + catch (CryptographicException) + { + _supportsSha1Signatures = false; + } + finally + { + rsa.Dispose(); + } + } + else + { + // Currently all non-Linux OSes support RSA-SHA1. + _supportsSha1Signatures = true; + } + } + + return _supportsSha1Signatures.Value; + } + } + public bool SupportsLargeExponent => true; public bool SupportsSha2Oaep { get; } = true; From 1dc77ac9b7a659bb2cb8327f65b92255d9d0eeb8 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Thu, 14 Apr 2022 10:28:27 -0400 Subject: [PATCH 2/5] Some X509Certificates fixes --- .../tests/CtorTests.cs | 18 +++++++++--------- .../tests/PfxTests.cs | 6 +++--- .../tests/TestData.cs | 10 +++++----- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/CtorTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/CtorTests.cs index 4da9a049088b66..254eef6c5b057e 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/CtorTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/CtorTests.cs @@ -189,9 +189,9 @@ public static void TestCopyConstructor_Lifetime_Independent() using (var c2 = new X509Certificate2(TestData.PfxData, TestData.PfxDataPassword)) { RSA rsa = c2.GetRSAPrivateKey(); - byte[] hash = new byte[20]; - byte[] sig = rsa.SignHash(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); - Assert.Equal(TestData.PfxSha1Empty_ExpectedSig, sig); + byte[] hash = new byte[SHA256.HashSizeInBytes]; + byte[] sig = rsa.SignHash(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + Assert.Equal(TestData.PfxSha256Empty_ExpectedSig, sig); c1.Dispose(); rsa.Dispose(); @@ -202,9 +202,9 @@ public static void TestCopyConstructor_Lifetime_Independent() // Verify other cert and previous key do not affect cert using (rsa = c2.GetRSAPrivateKey()) { - hash = new byte[20]; - sig = rsa.SignHash(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); - Assert.Equal(TestData.PfxSha1Empty_ExpectedSig, sig); + hash = new byte[SHA256.HashSizeInBytes]; + sig = rsa.SignHash(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + Assert.Equal(TestData.PfxSha256Empty_ExpectedSig, sig); } } } @@ -259,9 +259,9 @@ private static void TestPrivateKey(X509Certificate2 c, bool expectSuccess) { using (RSA rsa = c.GetRSAPrivateKey()) { - byte[] hash = new byte[20]; - byte[] sig = rsa.SignHash(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); - Assert.Equal(TestData.PfxSha1Empty_ExpectedSig, sig); + byte[] hash = new byte[SHA256.HashSizeInBytes]; + byte[] sig = rsa.SignHash(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + Assert.Equal(TestData.PfxSha256Empty_ExpectedSig, sig); } } else diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxTests.cs index 1132d8d85a406b..b7d8b6de5116ac 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxTests.cs @@ -134,9 +134,9 @@ public static void TestPrivateKeyProperty() private static void VerifyPrivateKey(RSA rsa) { - byte[] hash = new byte[20]; - byte[] sig = rsa.SignHash(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); - Assert.Equal(TestData.PfxSha1Empty_ExpectedSig, sig); + byte[] hash = new byte[SHA256.HashSizeInBytes]; + byte[] sig = rsa.SignHash(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + Assert.Equal(TestData.PfxSha256Empty_ExpectedSig, sig); } [Theory] diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/TestData.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/TestData.cs index 8673bf5fca616b..a0151384fe999a 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/TestData.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/TestData.cs @@ -173,11 +173,11 @@ public static SecureString CreatePfxDataPasswordSecureString() return s; } - public static readonly byte[] PfxSha1Empty_ExpectedSig = ( - "44b15120b8c7de19b4968d761600ffb8c54e5d0c1bcaba0880a20ab48912c8fd" + - "fa81b28134eabf58f3211a0d1eefdaae115e7872d5a67045c3b62a5da4393940" + - "e5a496413a6d55ea6309d0013e90657c83c6e40aa8fafeee66acbb6661c14190" + - "11e1fde6f4fcc328bd7e537e4aa2dbe216d8f1f3aa7e5ec60eb9cfdca7a41d74").HexToByteArray(); + public static readonly byte[] PfxSha256Empty_ExpectedSig = ( + "35306b63fbfe8eaf8e32937432e366d255461b02fb9e77368df319b99a8273cc" + + "dad52a21e8ae9c5df97ffa877d6c3ef6eb8a27ac7bbc93efdddd5dda9cf8d30e" + + "c52a76c7b2f9e478efe272d6e6f474033fb854e5685c44898367af860d5c893c" + + "56f89a69b84cd53434457de3296f80fbbe4eb938b4066b51638e35bce1e1c308").HexToByteArray(); private static readonly byte[] PfxData_RC2ContentEncryption = ( "3082063A020103308205F606092A864886F70D010701A08205E7048205E33082" + From 32531d4ce315eab29e223fab76425f86980a25c7 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Thu, 14 Apr 2022 12:58:23 -0400 Subject: [PATCH 3/5] Get S.S.C.Csp passing --- .../Security/Cryptography/SignatureSupport.cs | 51 +++++++++++++++++++ ...tem.Security.Cryptography.Cng.Tests.csproj | 2 + .../RSACryptoServiceProviderBackCompat.cs | 36 ++++++------- .../tests/RSACryptoServiceProviderProvider.cs | 5 +- .../tests/RSACryptoServiceProviderTests.cs | 23 +++++---- ...tem.Security.Cryptography.Csp.Tests.csproj | 2 + .../tests/RSAOpenSslProvider.cs | 37 ++------------ ...Security.Cryptography.OpenSsl.Tests.csproj | 2 + .../tests/DefaultRSAProvider.cs | 36 +------------ .../System.Security.Cryptography.Tests.csproj | 2 + 10 files changed, 100 insertions(+), 96 deletions(-) create mode 100644 src/libraries/Common/tests/System/Security/Cryptography/SignatureSupport.cs diff --git a/src/libraries/Common/tests/System/Security/Cryptography/SignatureSupport.cs b/src/libraries/Common/tests/System/Security/Cryptography/SignatureSupport.cs new file mode 100644 index 00000000000000..abdbabb14b8433 --- /dev/null +++ b/src/libraries/Common/tests/System/Security/Cryptography/SignatureSupport.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Security.Cryptography.Tests +{ + internal static class SignatureSupport + { + internal static bool CanProduceSha1Signature(AsymmetricAlgorithm algorithm) + { + // We expect all non-Linux platforms to support SHA1 signatures, currently. + if (!OperatingSystem.IsLinux()) + { + return true; + } + + switch (algorithm) + { + case ECDsa ecdsa: + try + { + ecdsa.SignData(Array.Empty(), HashAlgorithmName.SHA1); + return true; + } + catch (CryptographicException) + { + return false; + } + finally + { + algorithm.Dispose(); + } + case RSA rsa: + try + { + rsa.SignData(Array.Empty(), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + return true; + } + catch (CryptographicException) + { + return false; + } + finally + { + algorithm.Dispose(); + } + default: + throw new NotSupportedException($"Algorithm type {algorithm.GetType()} is not supported."); + } + } + } +} diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj b/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj index b2c8ebf7aab8a9..aaec2eb1c432cb 100644 --- a/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj @@ -15,6 +15,8 @@ + AlgorithmIdentifiers() { - return new[] + yield return new object[] { "MD5", MD5.Create() }; + yield return new object[] { "MD5", typeof(MD5) }; + yield return new object[] { "MD5", "1.2.840.113549.2.5" }; + + if (RSACryptoServiceProviderTests.IsSha1Supported) { - new object[] { "MD5", MD5.Create() }, - new object[] { "MD5", typeof(MD5) }, - new object[] { "MD5", "1.2.840.113549.2.5" }, - new object[] { "SHA1", SHA1.Create() }, - new object[] { "SHA1", typeof(SHA1) }, - new object[] { "SHA1", "1.3.14.3.2.26" }, - new object[] { "SHA256", SHA256.Create() }, - new object[] { "SHA256", typeof(SHA256) }, - new object[] { "SHA256", "2.16.840.1.101.3.4.2.1" }, - new object[] { "SHA384", SHA384.Create() }, - new object[] { "SHA384", typeof(SHA384) }, - new object[] { "SHA384", "2.16.840.1.101.3.4.2.2" }, - new object[] { "SHA512", SHA512.Create() }, - new object[] { "SHA512", typeof(SHA512) }, - new object[] { "SHA512", "2.16.840.1.101.3.4.2.3" }, - }; + yield return new object[] { "SHA1", SHA1.Create() }; + yield return new object[] { "SHA1", typeof(SHA1) }; + yield return new object[] { "SHA1", "1.3.14.3.2.26" }; + } + + yield return new object[] { "SHA256", SHA256.Create() }; + yield return new object[] { "SHA256", typeof(SHA256) }; + yield return new object[] { "SHA256", "2.16.840.1.101.3.4.2.1" }; + yield return new object[] { "SHA384", SHA384.Create() }; + yield return new object[] { "SHA384", typeof(SHA384) }; + yield return new object[] { "SHA384", "2.16.840.1.101.3.4.2.2" }; + yield return new object[] { "SHA512", SHA512.Create() }; + yield return new object[] { "SHA512", typeof(SHA512) }; + yield return new object[] { "SHA512", "2.16.840.1.101.3.4.2.3" }; } } } diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs b/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs index 3efd5501121863..7f4f3eb5b7d462 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs +++ b/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs @@ -2,11 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.InteropServices; +using System.Security.Cryptography.Tests; namespace System.Security.Cryptography.Rsa.Tests { public class RSACryptoServiceProviderProvider : IRSAProvider { + private bool? _supportsSha1Signatures; + public RSA Create() => new RSACryptoServiceProvider(); public RSA Create(int keySize) => new RSACryptoServiceProvider(keySize); @@ -19,7 +22,7 @@ public class RSACryptoServiceProviderProvider : IRSAProvider public bool SupportsPss => false; - public bool SupportsSha1Signatures => true; + public bool SupportsSha1Signatures => _supportsSha1Signatures ??= SignatureSupport.CanProduceSha1Signature(Create()); } public partial class RSAFactory diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderTests.cs b/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderTests.cs index b16d5e66d39eef..9ab96a959dcd82 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderTests.cs +++ b/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Security.Cryptography.Tests; using System.Security.Cryptography.Rsa.Tests; using Xunit; @@ -8,6 +9,8 @@ namespace System.Security.Cryptography.Csp.Tests { public class RSACryptoServiceProviderTests { + public static bool IsSha1Supported { get; } = SignatureSupport.CanProduceSha1Signature(new RSACryptoServiceProvider()); + const int PROV_RSA_FULL = 1; const int PROV_RSA_AES = 24; @@ -305,7 +308,7 @@ public static void ImportParameters_ExponentTooBig_Throws() } } - [Fact] + [ConditionalFact(nameof(IsSha1Supported))] public static void SignHash_DefaultAlgorithm_Success() { byte[] hashVal = SHA1.HashData(TestData.HelloBytes); @@ -317,7 +320,7 @@ public static void SignHash_DefaultAlgorithm_Success() } } - [Fact] + [ConditionalFact(nameof(IsSha1Supported))] public static void VerifyHash_DefaultAlgorithm_Success() { byte[] hashVal = SHA1.HashData(TestData.HelloBytes); @@ -352,7 +355,7 @@ public static void Sign_InvalidPaddingMode_Throws() { using (var rsa = new RSACryptoServiceProvider()) { - Assert.Throws(() => rsa.SignData(TestData.HelloBytes, HashAlgorithmName.SHA1, RSASignaturePadding.Pss)); + Assert.Throws(() => rsa.SignData(TestData.HelloBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pss)); } } @@ -361,8 +364,8 @@ public static void Verify_InvalidPaddingMode_Throws() { using (var rsa = new RSACryptoServiceProvider()) { - byte[] sig = rsa.SignData(TestData.HelloBytes, "SHA1"); - Assert.Throws(() => rsa.VerifyData(TestData.HelloBytes, sig, HashAlgorithmName.SHA1, RSASignaturePadding.Pss)); + byte[] sig = rsa.SignData(TestData.HelloBytes, "SHA256"); + Assert.Throws(() => rsa.VerifyData(TestData.HelloBytes, sig, HashAlgorithmName.SHA256, RSASignaturePadding.Pss)); } } @@ -378,15 +381,15 @@ public static void SignatureAlgorithm_Success() [Fact] public static void SignData_VerifyHash_CaseInsensitive_Success() { - byte[] hashVal = SHA1.HashData(TestData.HelloBytes); + byte[] hashVal = SHA256.HashData(TestData.HelloBytes); using (var rsa = new RSACryptoServiceProvider()) { - byte[] signVal = rsa.SignData(TestData.HelloBytes, "SHA1"); - Assert.True(rsa.VerifyHash(hashVal, "SHA1", signVal)); + byte[] signVal = rsa.SignData(TestData.HelloBytes, "SHA256"); + Assert.True(rsa.VerifyHash(hashVal, "SHA256", signVal)); - signVal = rsa.SignData(TestData.HelloBytes, "sha1"); - Assert.True(rsa.VerifyHash(hashVal, "sha1", signVal)); + signVal = rsa.SignData(TestData.HelloBytes, "sha256"); + Assert.True(rsa.VerifyHash(hashVal, "sha256", signVal)); } } diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj b/src/libraries/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj index 2343260ca112b0..ca7460db9b2d76 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj @@ -12,6 +12,8 @@ + true; - public bool SupportsSha1Signatures - { - get - { - if (!_supportsSha1Signatures.HasValue) - { - if (OperatingSystem.IsLinux()) - { - RSA rsa = Create(); - - try - { - rsa.SignData(Array.Empty(), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); - _supportsSha1Signatures = true; - } - catch (CryptographicException) - { - _supportsSha1Signatures = false; - } - finally - { - rsa.Dispose(); - } - } - else - { - // Currently all non-Linux OSes support RSA-SHA1. - _supportsSha1Signatures = true; - } - } - - return _supportsSha1Signatures.Value; - } - } + public bool SupportsSha1Signatures => _supportsSha1Signatures ??= SignatureSupport.CanProduceSha1Signature(Create()); } public partial class RSAFactory diff --git a/src/libraries/System.Security.Cryptography.OpenSsl/tests/System.Security.Cryptography.OpenSsl.Tests.csproj b/src/libraries/System.Security.Cryptography.OpenSsl/tests/System.Security.Cryptography.OpenSsl.Tests.csproj index 676580f1349553..b9ca6fa4508f1a 100644 --- a/src/libraries/System.Security.Cryptography.OpenSsl/tests/System.Security.Cryptography.OpenSsl.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.OpenSsl/tests/System.Security.Cryptography.OpenSsl.Tests.csproj @@ -18,6 +18,8 @@ Link="CommonTest\System\Security\Cryptography\ByteUtils.cs" /> + (), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); - _supportsSha1Signatures = true; - } - catch (CryptographicException) - { - _supportsSha1Signatures = false; - } - finally - { - rsa.Dispose(); - } - } - else - { - // Currently all non-Linux OSes support RSA-SHA1. - _supportsSha1Signatures = true; - } - } - - return _supportsSha1Signatures.Value; - } - } + public bool SupportsSha1Signatures => _supportsSha1Signatures ??= SignatureSupport.CanProduceSha1Signature(Create()); public bool SupportsLargeExponent => true; 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 b672db1d9ecd1f..6fa63793c4d82b 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 @@ -28,6 +28,8 @@ Link="ProductionCode\Common\System\Net\MultiArrayBuffer.cs" /> + Date: Wed, 27 Apr 2022 13:41:33 -0400 Subject: [PATCH 4/5] Remove duplicate property --- .../tests/RSACryptoServiceProviderBackCompat.cs | 2 +- .../tests/RSACryptoServiceProviderTests.cs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderBackCompat.cs b/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderBackCompat.cs index d172e8dde13afe..887bdc3d983e2e 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderBackCompat.cs +++ b/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderBackCompat.cs @@ -160,7 +160,7 @@ public static IEnumerable AlgorithmIdentifiers() yield return new object[] { "MD5", typeof(MD5) }; yield return new object[] { "MD5", "1.2.840.113549.2.5" }; - if (RSACryptoServiceProviderTests.IsSha1Supported) + if (RSAFactory.SupportsSha1Signatures) { yield return new object[] { "SHA1", SHA1.Create() }; yield return new object[] { "SHA1", typeof(SHA1) }; diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderTests.cs b/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderTests.cs index 9ab96a959dcd82..89c9405d84b4d8 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderTests.cs +++ b/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderTests.cs @@ -9,8 +9,6 @@ namespace System.Security.Cryptography.Csp.Tests { public class RSACryptoServiceProviderTests { - public static bool IsSha1Supported { get; } = SignatureSupport.CanProduceSha1Signature(new RSACryptoServiceProvider()); - const int PROV_RSA_FULL = 1; const int PROV_RSA_AES = 24; @@ -308,7 +306,7 @@ public static void ImportParameters_ExponentTooBig_Throws() } } - [ConditionalFact(nameof(IsSha1Supported))] + [ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))] public static void SignHash_DefaultAlgorithm_Success() { byte[] hashVal = SHA1.HashData(TestData.HelloBytes); @@ -320,7 +318,7 @@ public static void SignHash_DefaultAlgorithm_Success() } } - [ConditionalFact(nameof(IsSha1Supported))] + [ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))] public static void VerifyHash_DefaultAlgorithm_Success() { byte[] hashVal = SHA1.HashData(TestData.HelloBytes); From 167397f27ea5300d3f16811e0e73681c3c047cd1 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Wed, 27 Apr 2022 18:22:56 -0400 Subject: [PATCH 5/5] Start CI from scratch