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

Commit 39fb86f

Browse files
committed
Merge pull request #2712 from AtsushiKan/rsacngfixes
Add the common RSA tests to RSACng.Test.
2 parents f5b65d2 + f5e59d3 commit 39fb86f

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)