Add tests for exercising certificates with platform provider keys (#80558)
authorKevin Jones <kevin@vcsjones.com>
Mon, 16 Jan 2023 10:36:41 +0000 (05:36 -0500)
committerGitHub <noreply@github.com>
Mon, 16 Jan 2023 10:36:41 +0000 (11:36 +0100)
* Add tests for exercising certificate with platform provider keys.

* Refactor CngKey PCP test key creation

src/libraries/Common/tests/System/Security/Cryptography/CngPlatformProviderKey.cs [new file with mode: 0644]
src/libraries/System.Security.Cryptography.Cng/tests/ECDiffieHellmanCngTests.cs
src/libraries/System.Security.Cryptography.Cng/tests/PropertyTests.cs
src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj
src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj
src/libraries/System.Security.Cryptography/tests/X509Certificates/CertTests.cs

diff --git a/src/libraries/Common/tests/System/Security/Cryptography/CngPlatformProviderKey.cs b/src/libraries/Common/tests/System/Security/Cryptography/CngPlatformProviderKey.cs
new file mode 100644 (file)
index 0000000..b33636a
--- /dev/null
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Security.Cryptography;
+
+namespace Test.Cryptography
+{
+    internal sealed class CngPlatformProviderKey : IDisposable
+    {
+        public CngPlatformProviderKey(
+            CngAlgorithm algorithm,
+            string keySuffix = null,
+            [CallerMemberName] string testName = null,
+            params CngProperty[] additionalParameters)
+        {
+            CngKeyCreationParameters cngCreationParameters = new CngKeyCreationParameters
+            {
+                Provider = CngProvider.MicrosoftPlatformCryptoProvider,
+                KeyCreationOptions = CngKeyCreationOptions.OverwriteExistingKey,
+            };
+
+            foreach (CngProperty parameter in additionalParameters)
+            {
+                cngCreationParameters.Parameters.Add(parameter);
+            }
+
+            Key = CngKey.Create(algorithm, $"{testName}{algorithm.Algorithm}{keySuffix}", cngCreationParameters);
+        }
+
+        internal CngKey Key { get; }
+
+        public void Dispose()
+        {
+            Key.Delete();
+        }
+    }
+}
index 6d5406ef67a3990a2abea37fea1d6628f0c23472..638a7d4c95a97ad08ad62ed5a14a357352f42dc0 100644 (file)
@@ -193,39 +193,14 @@ namespace System.Security.Cryptography.EcDiffieHellman.Tests
         [OuterLoop("Hardware backed key generation takes several seconds.")]
         public static void PlatformCryptoProvider_DeriveKeyMaterial()
         {
-            CngKey key1 = null;
-            CngKey key2 = null;
-
-            try
-            {
-                CngKeyCreationParameters cngCreationParameters = new CngKeyCreationParameters
-                {
-                    Provider = CngProvider.MicrosoftPlatformCryptoProvider,
-                    KeyCreationOptions = CngKeyCreationOptions.OverwriteExistingKey,
-                };
-
-                key1 = CngKey.Create(
-                    CngAlgorithm.ECDiffieHellmanP256,
-                    $"{nameof(PlatformCryptoProvider_DeriveKeyMaterial)}{nameof(key1)}",
-                    cngCreationParameters);
-
-                key2 = CngKey.Create(
-                    CngAlgorithm.ECDiffieHellmanP256,
-                    $"{nameof(PlatformCryptoProvider_DeriveKeyMaterial)}{nameof(key2)}",
-                    cngCreationParameters);
-
-                using (ECDiffieHellmanCng ecdhCng1 = new ECDiffieHellmanCng(key1))
-                using (ECDiffieHellmanCng ecdhCng2 = new ECDiffieHellmanCng(key2))
-                {
-                    byte[] derivedKey1 = ecdhCng1.DeriveKeyMaterial(key2);
-                    byte[] derivedKey2 = ecdhCng2.DeriveKeyMaterial(key1);
-                    Assert.Equal(derivedKey1, derivedKey2);
-                }
-            }
-            finally
+            using (CngPlatformProviderKey platformKey1 = new CngPlatformProviderKey(CngAlgorithm.ECDiffieHellmanP256, "key1"))
+            using (CngPlatformProviderKey platformKey2 = new CngPlatformProviderKey(CngAlgorithm.ECDiffieHellmanP256, "key2"))
+            using (ECDiffieHellmanCng ecdhCng1 = new ECDiffieHellmanCng(platformKey1.Key))
+            using (ECDiffieHellmanCng ecdhCng2 = new ECDiffieHellmanCng(platformKey2.Key))
             {
-                key1?.Delete();
-                key2?.Delete();
+                byte[] derivedKey1 = ecdhCng1.DeriveKeyMaterial(platformKey2.Key);
+                byte[] derivedKey2 = ecdhCng2.DeriveKeyMaterial(platformKey1.Key);
+                Assert.Equal(derivedKey1, derivedKey2);
             }
         }
     }
index f37f7f8bedfa8b2d35a6f7c38116163054a4ab84..c6224678c46adeb995f645d5ada8e6dd5d3df74a 100644 (file)
@@ -17,24 +17,11 @@ namespace System.Security.Cryptography.Cng.Tests
         [OuterLoop("Hardware backed key generation takes several seconds.")]
         public static void CreatePersisted_PlatformEccKeyHasKeySize(string algorithm, int expectedKeySize)
         {
-            CngKey key = null;
+            CngAlgorithm cngAlgorithm = new CngAlgorithm(algorithm);
 
-            try
+            using (CngPlatformProviderKey platformKey = new CngPlatformProviderKey(cngAlgorithm))
             {
-                key = CngKey.Create(
-                    new CngAlgorithm(algorithm),
-                    $"{nameof(CreatePersisted_PlatformEccKeyHasKeySize)}_{algorithm}",
-                    new CngKeyCreationParameters
-                    {
-                        Provider = CngProvider.MicrosoftPlatformCryptoProvider,
-                        KeyCreationOptions = CngKeyCreationOptions.OverwriteExistingKey,
-                    });
-
-                Assert.Equal(expectedKeySize, key.KeySize);
-            }
-            finally
-            {
-                key?.Delete(); // Delete does a Dispose for us.
+                Assert.Equal(expectedKeySize, platformKey.Key.KeySize);
             }
         }
 
@@ -44,27 +31,15 @@ namespace System.Security.Cryptography.Cng.Tests
         [OuterLoop("Hardware backed key generation takes several seconds.")]
         public static void CreatePersisted_PlatformRsaKeyHasKeySize(int keySize)
         {
-            CngKey key = null;
+            CngProperty keyLengthProperty = new CngProperty("Length", BitConverter.GetBytes(keySize), CngPropertyOptions.None);
+            CngPlatformProviderKey platformKey = new CngPlatformProviderKey(
+                CngAlgorithm.Rsa,
+                keySuffix: keySize.ToString(),
+                additionalParameters: keyLengthProperty);
 
-            try
-            {
-                CngKeyCreationParameters cngCreationParameters = new CngKeyCreationParameters
-                {
-                    Provider = CngProvider.MicrosoftPlatformCryptoProvider,
-                    KeyCreationOptions = CngKeyCreationOptions.OverwriteExistingKey,
-                };
-                cngCreationParameters.Parameters.Add(new CngProperty("Length", BitConverter.GetBytes(keySize), CngPropertyOptions.None));
-
-                key = CngKey.Create(
-                    CngAlgorithm.Rsa,
-                    $"{nameof(CreatePersisted_PlatformRsaKeyHasKeySize)}_{keySize}",
-                    cngCreationParameters);
-
-                Assert.Equal(keySize, key.KeySize);
-            }
-            finally
+            using (platformKey)
             {
-                key?.Delete(); // Delete does a Dispose for us.
+                Assert.Equal(keySize, platformKey.Key.KeySize);
             }
         }
 
index 4bfc1719abf9d87e0eb1e9abe5f2cf09ec4496b3..8bd0699feeb6d6a8697cfc62b3b338c1424753f2 100644 (file)
@@ -42,6 +42,8 @@
              Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanFactory.cs" />
     <Compile Include="$(CommonTestPath)System\Security\Cryptography\ByteUtils.cs"
              Link="CommonTest\System\Security\Cryptography\ByteUtils.cs" />
+    <Compile Include="$(CommonTestPath)System\Security\Cryptography\CngPlatformProviderKey.cs"
+             Link="CommonTest\System\Security\Cryptography\CngPlatformProviderKey.cs" />
     <Compile Include="$(CommonTestPath)System\Security\Cryptography\CryptoUtils.cs"
              Link="CommonTest\System\Security\Cryptography\CryptoUtils.cs" />
     <Compile Include="$(CommonTestPath)System\Security\Cryptography\PlatformSupport.cs"
index a24845e6891c85cd3aafb2b2506811d01dd76971..3165257e70267224b1116f7270b4a8a5e61e5cb4 100644 (file)
              Link="CommonTest\System\Security\Cryptography\509Certificates\RevocationResponder.cs" />
     <Compile Include="$(CommonTestPath)System\Security\Cryptography\ByteUtils.cs"
              Link="CommonTest\System\Security\Cryptography\ByteUtils.cs" />
+    <Compile Include="$(CommonTestPath)System\Security\Cryptography\CngPlatformProviderKey.cs"
+             Link="CommonTest\System\Security\Cryptography\CngPlatformProviderKey.cs" />
     <Compile Include="$(CommonTestPath)System\Security\Cryptography\CryptoUtils.cs"
              Link="CommonTest\System\Security\Cryptography\CryptoUtils.cs" />
     <Compile Include="$(CommonTestPath)System\Security\Cryptography\PlatformSupport.cs"
index ed0db080a5cf65127fc657a25affef3b00c942cd..1e7ffd9ec535fa407b505fcd6458c6d71772655d 100644 (file)
@@ -571,6 +571,48 @@ namespace System.Security.Cryptography.X509Certificates.Tests
             }
         }
 
+        [ConditionalFact(typeof(PlatformSupport), nameof(PlatformSupport.PlatformCryptoProviderFunctional))]
+        [OuterLoop("Hardware backed key generation takes several seconds.")]
+        public static void CreateCertificate_MicrosoftPlatformCryptoProvider_EcdsaKey()
+        {
+            using (CngPlatformProviderKey platformKey = new CngPlatformProviderKey(CngAlgorithm.ECDsaP384))
+            using (ECDsaCng ecdsa = new ECDsaCng(platformKey.Key))
+            {
+                CertificateRequest req = new CertificateRequest("CN=potato", ecdsa, HashAlgorithmName.SHA256);
+
+                using (X509Certificate2 cert = req.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow))
+                using (ECDsa certKey = cert.GetECDsaPrivateKey())
+                {
+                    Assert.NotNull(certKey);
+                    byte[] data = new byte[] { 12, 11, 02, 08, 25, 14, 11, 18, 16 };
+                    byte[] signature = certKey.SignData(data, HashAlgorithmName.SHA256);
+                    bool valid = ecdsa.VerifyData(data, signature, HashAlgorithmName.SHA256);
+                    Assert.True(valid, "valid signature");
+                }
+            }
+        }
+
+        [ConditionalFact(typeof(PlatformSupport), nameof(PlatformSupport.PlatformCryptoProviderFunctional))]
+        [OuterLoop("Hardware backed key generation takes several seconds.")]
+        public static void CreateCertificate_MicrosoftPlatformCryptoProvider_RsaKey()
+        {
+            using (CngPlatformProviderKey platformKey = new CngPlatformProviderKey(CngAlgorithm.Rsa))
+            using (RSACng rsa = new RSACng(platformKey.Key))
+            {
+                CertificateRequest req = new CertificateRequest("CN=potato", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
+
+                using (X509Certificate2 cert = req.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow))
+                using (RSA certKey = cert.GetRSAPrivateKey())
+                {
+                    Assert.NotNull(certKey);
+                    byte[] data = new byte[] { 12, 11, 02, 08, 25, 14, 11, 18, 16 };
+                    byte[] signature = certKey.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
+                    bool valid = rsa.VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
+                    Assert.True(valid, "valid signature");
+                }
+            }
+        }
+
         public static IEnumerable<object[]> StorageFlags => CollectionImportTests.StorageFlags;
     }
 }