Skip to content

Commit

Permalink
Condition S.S.Cryptography tests on SHA1 signature support
Browse files Browse the repository at this point in the history
  • Loading branch information
vcsjones authored Apr 28, 2022
1 parent c504512 commit 0a2bc2f
Show file tree
Hide file tree
Showing 18 changed files with 171 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public interface IRSAProvider
bool SupportsLargeExponent { get; }
bool SupportsSha2Oaep { get; }
bool SupportsPss { get; }
bool SupportsSha1Signatures { get; }
}

public static partial class RSAFactory
Expand Down Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down Expand Up @@ -66,7 +66,7 @@ public static void InvalidHashAlgorithm()
}
}

[Fact]
[ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))]
public static void VerifyKnownSignature()
{
byte[] hash = "012d161304fa0c6321221516415813022320620c".HexToByteArray();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Collections.Generic;
using System.IO;
using Microsoft.DotNet.XUnitExtensions;
using Test.Cryptography;
using Test.IO.Streams;
using Xunit;
Expand All @@ -26,14 +27,14 @@ public void NullArray_Throws()
{
using (RSA rsa = RSAFactory.Create())
{
AssertExtensions.Throws<ArgumentNullException>("data", () => SignData(rsa, null, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1));
AssertExtensions.Throws<ArgumentNullException>("hash", () => SignHash(rsa, null, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1));
AssertExtensions.Throws<ArgumentNullException>("data", () => SignData(rsa, null, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
AssertExtensions.Throws<ArgumentNullException>("hash", () => SignHash(rsa, null, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));

AssertExtensions.Throws<ArgumentNullException>("data", () => VerifyData(rsa, null, new byte[1], HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1));
AssertExtensions.Throws<ArgumentNullException>("hash", () => VerifyHash(rsa, null, new byte[1], HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1));
AssertExtensions.Throws<ArgumentNullException>("data", () => VerifyData(rsa, null, new byte[1], HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
AssertExtensions.Throws<ArgumentNullException>("hash", () => VerifyHash(rsa, null, new byte[1], HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));

AssertExtensions.Throws<ArgumentNullException>("signature", () => VerifyData(rsa, new byte[1], null, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1));
AssertExtensions.Throws<ArgumentNullException>("signature", () => VerifyHash(rsa, new byte[1], null, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1));
AssertExtensions.Throws<ArgumentNullException>("signature", () => VerifyData(rsa, new byte[1], null, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
AssertExtensions.Throws<ArgumentNullException>("signature", () => VerifyHash(rsa, new byte[1], null, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
}
}
}
Expand Down Expand Up @@ -72,10 +73,10 @@ public void NullPadding_Throws()
{
using (RSA rsa = RSAFactory.Create())
{
AssertExtensions.Throws<ArgumentNullException>("padding", () => SignData(rsa, new byte[1], HashAlgorithmName.SHA1, null));
AssertExtensions.Throws<ArgumentNullException>("padding", () => SignHash(rsa, new byte[1], HashAlgorithmName.SHA1, null));
AssertExtensions.Throws<ArgumentNullException>("padding", () => VerifyData(rsa, new byte[1], new byte[1], HashAlgorithmName.SHA1, null));
AssertExtensions.Throws<ArgumentNullException>("padding", () => VerifyHash(rsa, new byte[1], new byte[1], HashAlgorithmName.SHA1, null));
AssertExtensions.Throws<ArgumentNullException>("padding", () => SignData(rsa, new byte[1], HashAlgorithmName.SHA256, null));
AssertExtensions.Throws<ArgumentNullException>("padding", () => SignHash(rsa, new byte[1], HashAlgorithmName.SHA256, null));
AssertExtensions.Throws<ArgumentNullException>("padding", () => VerifyData(rsa, new byte[1], new byte[1], HashAlgorithmName.SHA256, null));
AssertExtensions.Throws<ArgumentNullException>("padding", () => VerifyHash(rsa, new byte[1], new byte[1], HashAlgorithmName.SHA256, null));
}
}

Expand All @@ -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)
Expand Down Expand Up @@ -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<CryptographicException>(() => 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));
}
}

Expand All @@ -143,11 +144,11 @@ public void SignEmptyHash()
using (RSA rsa = RSAFactory.Create())
{
Assert.ThrowsAny<CryptographicException>(
() => SignHash(rsa, Array.Empty<byte>(), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1));
() => SignHash(rsa, Array.Empty<byte>(), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
}
}

[Fact]
[ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))]
public void ExpectedSignature_SHA1_384()
{
byte[] expectedSignature =
Expand Down Expand Up @@ -178,7 +179,7 @@ public void ExpectedSignature_SHA1_384()
}
}

[Fact]
[ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))]
public void ExpectedSignature_SHA1_1032()
{
byte[] expectedSignature =
Expand All @@ -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[]
Expand Down Expand Up @@ -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 =
Expand All @@ -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 =
Expand All @@ -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[]
Expand Down Expand Up @@ -516,8 +517,12 @@ public static IEnumerable<object[]> 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 };
}

Expand All @@ -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);
}
Expand All @@ -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);
}
}
Expand All @@ -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<byte>(), signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
byte[] signature = SignData(rsa, TestData.HelloBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
bool signatureMatched = VerifyData(rsa, Array.Empty<byte>(), signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
Assert.False(signatureMatched);
}
}
Expand All @@ -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);
}
Expand Down Expand Up @@ -610,7 +615,7 @@ public void PkcsSignHash_MismatchedHashSize()
}
}

[Fact]
[ConditionalFact(typeof(RSAFactory), nameof(RSAFactory.SupportsSha1Signatures))]
public void ExpectedHashSignature_SHA1_2048()
{
byte[] expectedHashSignature = new byte[]
Expand Down Expand Up @@ -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[]
Expand Down Expand Up @@ -872,14 +877,19 @@ public void VerifyHashSignature_SHA256_2048()
VerifyHashSignature(hashSignature, dataHash, "SHA256", TestData.RSA2048Params);
}

[Theory]
[ConditionalTheory]
[InlineData("SHA256")]
[InlineData("SHA384")]
[InlineData("SHA512")]
[InlineData("MD5")]
[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
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public static void VerifyDefaultSpanHash()
byte[] signature = new byte[2048 / 8];

Assert.False(
rsa.VerifyHash(ReadOnlySpan<byte>.Empty, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1));
rsa.VerifyHash(ReadOnlySpan<byte>.Empty, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));

if (RSAFactory.SupportsPss)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -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<byte>(), HashAlgorithmName.SHA1);
return true;
}
catch (CryptographicException)
{
return false;
}
finally
{
algorithm.Dispose();
}
case RSA rsa:
try
{
rsa.SignData(Array.Empty<byte>(), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
return true;
}
catch (CryptographicException)
{
return false;
}
finally
{
algorithm.Dispose();
}
default:
throw new NotSupportedException($"Algorithm type {algorithm.GetType()} is not supported.");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public bool Supports384PrivateKey
public bool SupportsSha2Oaep => true;

public bool SupportsPss => true;

public bool SupportsSha1Signatures => true;
}

public partial class RSAFactory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
<Compile Include="TestData.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'windows'">
<Compile Include="$(CommonTestPath)System\Security\Cryptography\SignatureSupport.cs"
Link="CommonTest\System\Security\Cryptography\SignatureSupport.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\AES\AesCipherTests.Data.cs"
Link="CommonTest\AlgorithmImplementations\AES\AesCipherTests.Data.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\AES\AesCornerTests.cs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,24 +156,26 @@ public static void VerifyLegacySignVerifyHash(bool useLegacySign, bool useLegacy

public static IEnumerable<object[]> 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 (RSAFactory.SupportsSha1Signatures)
{
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" };
}
}
}
Loading

0 comments on commit 0a2bc2f

Please sign in to comment.