Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit f5e59d3

Browse files
author
Atsushi Kanamori
committed
Unify the RSACng tests with the other RSA classes.
This required some fixes to RSACng that will need to be ported to 4.6. �Set the export policies so that ImportParameters(true) works. �Throw the right (or wrong, depending on your pov) exception if ImportParameters() is given an RSAParameters with null fields. �VerifyHash(). Don't throw CryptographicException if the hash doesn't verify. Just return false like the nice docs say.
1 parent b7eb52f commit f5e59d3

File tree

13 files changed

+170
-275
lines changed

13 files changed

+170
-275
lines changed

src/Common/tests/Cryptography/AlgorithmImplementations/RSA/ImportExport.cs

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace System.Security.Cryptography.Rsa.Tests
77
{
8-
public class ImportExport
8+
public partial class ImportExport
99
{
1010
[Fact]
1111
public static void ExportAutoKey()
@@ -37,33 +37,6 @@ public static void ExportAutoKey()
3737
Assert.Equal(privateParams.Exponent, publicParams.Exponent);
3838
}
3939

40-
[Fact]
41-
public static void PaddedExport()
42-
{
43-
// OpenSSL's numeric type for the storage of RSA key parts disregards zero-valued
44-
// prefix bytes.
45-
//
46-
// The .NET 4.5 RSACryptoServiceProvider type verifies that all of the D breakdown
47-
// values (P, DP, Q, DQ, InverseQ) are exactly half the size of D (which is itself
48-
// the same size as Modulus).
49-
//
50-
// These two things, in combination, suggest that we ensure that all .NET
51-
// implementations of RSA export their keys to the fixed array size suggested by their
52-
// KeySize property.
53-
RSAParameters diminishedDPParamaters = TestData.DiminishedDPParamaters;
54-
RSAParameters exported;
55-
56-
using (RSA rsa = RSAFactory.Create())
57-
{
58-
rsa.ImportParameters(diminishedDPParamaters);
59-
exported = rsa.ExportParameters(true);
60-
}
61-
62-
// DP is the most likely to fail, the rest just otherwise ensure that Export
63-
// isn't losing data.
64-
AssertKeyEquals(ref diminishedDPParamaters, ref exported);
65-
}
66-
6740
[Fact]
6841
public static void LargeKeyImportExport()
6942
{
@@ -93,30 +66,6 @@ public static void LargeKeyImportExport()
9366
}
9467
}
9568

96-
[Fact]
97-
public static void UnusualExponentImportExport()
98-
{
99-
// Most choices for the Exponent value in an RSA key use a Fermat prime.
100-
// Since a Fermat prime is 2^(2^m) + 1, it always only has two bits set, and
101-
// frequently has the form { 0x01, [some number of 0x00s], 0x01 }, which has the same
102-
// representation in both big- and little-endian.
103-
//
104-
// The only real requirement for an Exponent value is that it be coprime to (p-1)(q-1).
105-
// So here we'll use the (non-Fermat) prime value 433 (0x01B1) to ensure big-endian export.
106-
RSAParameters unusualExponentParameters = TestData.UnusualExponentParameters;
107-
RSAParameters exported;
108-
109-
using (RSA rsa = RSAFactory.Create())
110-
{
111-
rsa.ImportParameters(unusualExponentParameters);
112-
exported = rsa.ExportParameters(true);
113-
}
114-
115-
// Exponent is the most likely to fail, the rest just otherwise ensure that Export
116-
// isn't losing data.
117-
AssertKeyEquals(ref unusualExponentParameters, ref exported);
118-
}
119-
12069
[Fact]
12170
public static void ImportReset()
12271
{
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Xunit;
5+
6+
namespace System.Security.Cryptography.Rsa.Tests
7+
{
8+
//
9+
// These tests currently do not work against CNG and thus are split off so we can exclude them.
10+
//
11+
public partial class ImportExport
12+
{
13+
[Fact]
14+
public static void PaddedExport()
15+
{
16+
// OpenSSL's numeric type for the storage of RSA key parts disregards zero-valued
17+
// prefix bytes.
18+
//
19+
// The .NET 4.5 RSACryptoServiceProvider type verifies that all of the D breakdown
20+
// values (P, DP, Q, DQ, InverseQ) are exactly half the size of D (which is itself
21+
// the same size as Modulus).
22+
//
23+
// These two things, in combination, suggest that we ensure that all .NET
24+
// implementations of RSA export their keys to the fixed array size suggested by their
25+
// KeySize property.
26+
RSAParameters diminishedDPParamaters = TestData.DiminishedDPParamaters;
27+
RSAParameters exported;
28+
29+
using (RSA rsa = RSAFactory.Create())
30+
{
31+
rsa.ImportParameters(diminishedDPParamaters);
32+
exported = rsa.ExportParameters(true);
33+
}
34+
35+
// DP is the most likely to fail, the rest just otherwise ensure that Export
36+
// isn't losing data.
37+
AssertKeyEquals(ref diminishedDPParamaters, ref exported);
38+
}
39+
40+
[Fact]
41+
public static void UnusualExponentImportExport()
42+
{
43+
// Most choices for the Exponent value in an RSA key use a Fermat prime.
44+
// Since a Fermat prime is 2^(2^m) + 1, it always only has two bits set, and
45+
// frequently has the form { 0x01, [some number of 0x00s], 0x01 }, which has the same
46+
// representation in both big- and little-endian.
47+
//
48+
// The only real requirement for an Exponent value is that it be coprime to (p-1)(q-1).
49+
// So here we'll use the (non-Fermat) prime value 433 (0x01B1) to ensure big-endian export.
50+
RSAParameters unusualExponentParameters = TestData.UnusualExponentParameters;
51+
RSAParameters exported;
52+
53+
using (RSA rsa = RSAFactory.Create())
54+
{
55+
rsa.ImportParameters(unusualExponentParameters);
56+
exported = rsa.ExportParameters(true);
57+
}
58+
59+
// Exponent is the most likely to fail, the rest just otherwise ensure that Export
60+
// isn't losing data.
61+
AssertKeyEquals(ref unusualExponentParameters, ref exported);
62+
}
63+
}
64+
}

src/System.Security.Cryptography.Cng/src/Internal/Cryptography/Helpers.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,19 @@ public static IntPtr GetPropertyAsIntPtr(this SafeNCryptHandle ncryptHandle, str
139139
return value;
140140
}
141141
}
142+
143+
/// <summary>
144+
/// Modify a CNG key's export policy.
145+
/// </summary>
146+
public static void SetExportPolicy(this SafeNCryptKeyHandle keyHandle, CngExportPolicies exportPolicy)
147+
{
148+
unsafe
149+
{
150+
ErrorCode errorCode = Interop.NCrypt.NCryptSetProperty(keyHandle, KeyPropertyName.ExportPolicy, &exportPolicy, sizeof(CngExportPolicies), CngPropertyOptions.Persist);
151+
if (errorCode != ErrorCode.ERROR_SUCCESS)
152+
throw errorCode.ToCryptographicException();
153+
}
154+
}
142155
}
143156
}
144157

src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/CngKey.Create.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,14 @@ public static CngKey Create(CngAlgorithm algorithm, string keyName, CngKeyCreati
6767
/// <summary>
6868
/// Setup the key properties specified in the key creation parameters
6969
/// </summary>
70-
private static void InitializeKeyProperties(SafeNCryptHandle keyHandle, CngKeyCreationParameters creationParameters)
70+
private static void InitializeKeyProperties(SafeNCryptKeyHandle keyHandle, CngKeyCreationParameters creationParameters)
7171
{
7272
unsafe
7373
{
7474
if (creationParameters.ExportPolicy.HasValue)
7575
{
7676
CngExportPolicies exportPolicy = creationParameters.ExportPolicy.Value;
77-
ErrorCode errorCode = Interop.NCrypt.NCryptSetProperty(keyHandle, KeyPropertyName.ExportPolicy, &exportPolicy, sizeof(CngExportPolicies), CngPropertyOptions.Persist);
78-
if (errorCode != ErrorCode.ERROR_SUCCESS)
79-
throw errorCode.ToCryptographicException();
77+
keyHandle.SetExportPolicy(exportPolicy);
8078
}
8179

8280
if (creationParameters.KeyUsage.HasValue)
@@ -119,7 +117,7 @@ private static void InitializeKeyProperties(SafeNCryptHandle keyHandle, CngKeyCr
119117
/// <summary>
120118
/// Setup the UIPolicy key properties specified in the key creation parameters
121119
/// </summary>
122-
private static void InitializeKeyUiPolicyProperties(SafeNCryptHandle keyHandle, CngUIPolicy uiPolicy)
120+
private static void InitializeKeyUiPolicyProperties(SafeNCryptKeyHandle keyHandle, CngUIPolicy uiPolicy)
123121
{
124122
unsafe
125123
{

src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/CngKey.StandardProperties.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ public CngExportPolicies ExportPolicy
6464
CngExportPolicies policy = (CngExportPolicies)_keyHandle.GetPropertyAsDword(KeyPropertyName.ExportPolicy, CngPropertyOptions.None);
6565
return policy;
6666
}
67+
68+
internal set
69+
{
70+
_keyHandle.SetExportPolicy(value);
71+
}
6772
}
6873

6974
/// <summary>

src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/RSACng.ImportExport.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,21 @@ public override void ImportParameters(RSAParameters parameters)
3838
unsafe
3939
{
4040
if (parameters.Exponent == null || parameters.Modulus == null)
41-
throw new ArgumentException(SR.Cryptography_InvalidRsaParameters);
41+
throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
4242

43-
bool includePrivate = parameters.P != null && parameters.Q != null;
43+
bool includePrivate;
44+
if (parameters.D == null)
45+
{
46+
includePrivate = false;
47+
if (parameters.P != null || parameters.DP != null || parameters.Q != null || parameters.DQ != null || parameters.InverseQ != null)
48+
throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
49+
}
50+
else
51+
{
52+
includePrivate = true;
53+
if (parameters.P == null || parameters.DP == null || parameters.Q == null || parameters.DQ == null || parameters.InverseQ == null)
54+
throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
55+
}
4456

4557
//
4658
// We need to build a key blob structured as follows:
@@ -94,7 +106,11 @@ public override void ImportParameters(RSAParameters parameters)
94106
Debug.Assert(offset == blobSize, "offset == blobSize");
95107
}
96108
CngKeyBlobFormat blobFormat = includePrivate ? s_rsaPrivateBlob : s_rsaPublicBlob;
97-
Key = CngKey.Import(rsaBlob, blobFormat);
109+
110+
CngKey newKey = CngKey.Import(rsaBlob, blobFormat);
111+
newKey.ExportPolicy |= CngExportPolicies.AllowPlaintextExport;
112+
113+
Key = newKey;
98114
}
99115
}
100116

src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/RSACng.Key.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ public CngKey Key
3232
// If we don't have a key yet, we need to generate a random one now.
3333
if (_lazyKey == null)
3434
{
35-
CngKeyCreationParameters creationParameters = new CngKeyCreationParameters();
35+
CngKeyCreationParameters creationParameters = new CngKeyCreationParameters()
36+
{
37+
ExportPolicy = CngExportPolicies.AllowPlaintextExport,
38+
};
39+
3640
CngProperty keySizeProperty = new CngProperty(KeyPropertyName.Length, BitConverter.GetBytes(KeySize), CngPropertyOptions.None);
3741
creationParameters.Parameters.Add(keySizeProperty);
3842
_lazyKey = CngKey.Create(CngAlgorithm.Rsa, null, creationParameters);

src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/RSACng.SignVerify.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,7 @@ public override bool VerifyHash(byte[] hash, byte[] signature, HashAlgorithmName
6565
{
6666
SafeNCryptKeyHandle keyHandle = Key.Handle;
6767
ErrorCode errorCode = Interop.NCrypt.NCryptVerifySignature(keyHandle, pPaddingInfo, hash, hash.Length, signature, signature.Length, paddingMode);
68-
if (errorCode == ErrorCode.ERROR_SUCCESS)
69-
verified = true;
70-
else if (errorCode == ErrorCode.NTE_BAD_SIGNATURE)
71-
verified = false;
72-
else
73-
throw errorCode.ToCryptographicException();
68+
verified = (errorCode == ErrorCode.ERROR_SUCCESS); // For consistency with other RSA classes, return "false" for any error code rather than making the caller catch an exception.
7469
}
7570
);
7671
return verified;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
namespace System.Security.Cryptography.Rsa.Tests
5+
{
6+
public class RSACngProvider : IRSAProvider
7+
{
8+
public RSA Create()
9+
{
10+
return new RSACng();
11+
}
12+
13+
public RSA Create(int keySize)
14+
{
15+
return new RSACng(keySize);
16+
}
17+
}
18+
19+
public partial class RSAFactory
20+
{
21+
private static readonly IRSAProvider s_provider = new RSACngProvider();
22+
}
23+
}

0 commit comments

Comments
 (0)