diff --git a/build.proj b/build.proj
index efa250d1a0..32b26fbe58 100644
--- a/build.proj
+++ b/build.proj
@@ -59,6 +59,7 @@
+
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ExceptionsAlgorithmErrors.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ExceptionsAlgorithmErrors.cs
index e2d8e02b0b..ba90ddf4f0 100644
--- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ExceptionsAlgorithmErrors.cs
+++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ExceptionsAlgorithmErrors.cs
@@ -7,18 +7,38 @@
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
+using Microsoft.Data.SqlClient.TestUtilities.Fixtures;
using Xunit;
using static Microsoft.Data.SqlClient.Tests.AlwaysEncryptedTests.Utility;
namespace Microsoft.Data.SqlClient.Tests.AlwaysEncryptedTests
{
- public class ExceptionsAlgorithmErrors : IClassFixture
+ public class ExceptionsAlgorithmErrors : IClassFixture
{
// Reflection
public static Assembly systemData = Assembly.GetAssembly(typeof(SqlConnection));
public static Type sqlClientSymmetricKey = systemData.GetType("Microsoft.Data.SqlClient.SqlClientSymmetricKey");
public static ConstructorInfo sqlColumnEncryptionKeyConstructor = sqlClientSymmetricKey.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(byte[]) }, null);
+ private readonly ColumnEncryptionCertificateFixture _fixture;
+ private readonly byte[] _cek;
+ private readonly byte[] _encryptedCek;
+ private readonly string _certificatePath;
+
+ public ExceptionsAlgorithmErrors(ColumnEncryptionCertificateFixture fixture)
+ {
+ // Disable the cache to avoid false failures.
+ SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled = false;
+
+ SqlColumnEncryptionCertificateStoreProvider provider = new SqlColumnEncryptionCertificateStoreProvider();
+ X509Certificate2 currUserCertificate = fixture.GetCertificate(StoreLocation.CurrentUser);
+
+ _cek = GenerateRandomBytes(32);
+ _fixture = fixture;
+ _certificatePath = string.Format("CurrentUser/My/{0}", currUserCertificate.Thumbprint);
+ _encryptedCek = provider.EncryptColumnEncryptionKey(_certificatePath, "RSA_OAEP", _cek);
+ }
+
[Fact]
[PlatformSpecific(TestPlatforms.Windows)]
public void TestNullCEK()
@@ -52,9 +72,9 @@ public void TestInvalidEncryptionType()
{
const byte invalidEncryptionType = 3;
Object cipherMD = GetSqlCipherMetadata(0, 2, null, invalidEncryptionType, 0x01);
- AddEncryptionKeyToCipherMD(cipherMD, CertFixture.encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, CertFixture.certificatePath, "MSSQL_CERTIFICATE_STORE", "RSA_OAEP");
+ AddEncryptionKeyToCipherMD(cipherMD, _encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, _certificatePath, "MSSQL_CERTIFICATE_STORE", "RSA_OAEP");
byte[] plainText = Encoding.Unicode.GetBytes("HelloWorld");
- byte[] cipherText = EncryptDataUsingAED(plainText, CertFixture.cek, CColumnEncryptionType.Deterministic);
+ byte[] cipherText = EncryptDataUsingAED(plainText, _cek, CColumnEncryptionType.Deterministic);
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_InvalidEncryptionType,
"AEAD_AES_256_CBC_HMAC_SHA256", invalidEncryptionType, "'Deterministic', 'Randomized'");
@@ -74,7 +94,7 @@ public void TestInvalidCipherText()
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_InvalidCipherTextSize,
invalidCiphertextLength, 65);
byte[] cipherText = GenerateRandomBytes(invalidCiphertextLength); // minimum length is 65
- TargetInvocationException e = Assert.Throws(() => DecryptDataUsingAED(cipherText, CertFixture.cek, CColumnEncryptionType.Deterministic));
+ TargetInvocationException e = Assert.Throws(() => DecryptDataUsingAED(cipherText, _cek, CColumnEncryptionType.Deterministic));
Assert.Contains(expectedMessage, e.InnerException.Message);
}
@@ -85,10 +105,10 @@ public void TestInvalidAlgorithmVersion()
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_InvalidAlgorithmVersion,
40, "01");
byte[] plainText = Encoding.Unicode.GetBytes("Hello World");
- byte[] cipherText = EncryptDataUsingAED(plainText, CertFixture.cek, CColumnEncryptionType.Deterministic);
+ byte[] cipherText = EncryptDataUsingAED(plainText, _cek, CColumnEncryptionType.Deterministic);
// Put a version number of 0x10
cipherText[0] = 0x40;
- TargetInvocationException e = Assert.Throws(() => DecryptDataUsingAED(cipherText, CertFixture.cek, CColumnEncryptionType.Deterministic));
+ TargetInvocationException e = Assert.Throws(() => DecryptDataUsingAED(cipherText, _cek, CColumnEncryptionType.Deterministic));
Assert.Contains(expectedMessage, e.InnerException.Message);
}
@@ -98,13 +118,13 @@ public void TestInvalidAuthenticationTag()
{
string expectedMessage = SystemDataResourceManager.Instance.TCE_InvalidAuthenticationTag;
byte[] plainText = Encoding.Unicode.GetBytes("Hello World");
- byte[] cipherText = EncryptDataUsingAED(plainText, CertFixture.cek, CColumnEncryptionType.Deterministic);
+ byte[] cipherText = EncryptDataUsingAED(plainText, _cek, CColumnEncryptionType.Deterministic);
// Zero out 4 bytes of authentication tag
for (int i = 0; i < 4; i++)
{
cipherText[i + 1] = 0x00;
}
- TargetInvocationException e = Assert.Throws(() => DecryptDataUsingAED(cipherText, CertFixture.cek, CColumnEncryptionType.Deterministic));
+ TargetInvocationException e = Assert.Throws(() => DecryptDataUsingAED(cipherText, _cek, CColumnEncryptionType.Deterministic));
Assert.Contains(expectedMessage, e.InnerException.Message);
}
@@ -115,9 +135,9 @@ public void TestNullColumnEncryptionAlgorithm()
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_NullColumnEncryptionAlgorithm,
"'AEAD_AES_256_CBC_HMAC_SHA256'");
Object cipherMD = GetSqlCipherMetadata(0, 0, null, 1, 0x01);
- AddEncryptionKeyToCipherMD(cipherMD, CertFixture.encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, CertFixture.certificatePath, "MSSQL_CERTIFICATE_STORE", "RSA_OAEP");
+ AddEncryptionKeyToCipherMD(cipherMD, _encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, _certificatePath, "MSSQL_CERTIFICATE_STORE", "RSA_OAEP");
byte[] plainText = Encoding.Unicode.GetBytes("HelloWorld");
- byte[] cipherText = EncryptDataUsingAED(plainText, CertFixture.cek, CColumnEncryptionType.Deterministic);
+ byte[] cipherText = EncryptDataUsingAED(plainText, _cek, CColumnEncryptionType.Deterministic);
TargetInvocationException e = Assert.Throws(() => DecryptWithKey(cipherText, cipherMD));
Assert.Contains(expectedMessage, e.InnerException.Message);
@@ -133,9 +153,9 @@ public void TestUnknownEncryptionAlgorithmId()
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_UnknownColumnEncryptionAlgorithmId,
unknownEncryptionAlgoId, "'1', '2'");
Object cipherMD = GetSqlCipherMetadata(0, unknownEncryptionAlgoId, null, 1, 0x01);
- AddEncryptionKeyToCipherMD(cipherMD, CertFixture.encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, CertFixture.certificatePath, "MSSQL_CERTIFICATE_STORE", "RSA_OAEP");
+ AddEncryptionKeyToCipherMD(cipherMD, _encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, _certificatePath, "MSSQL_CERTIFICATE_STORE", "RSA_OAEP");
byte[] plainText = Encoding.Unicode.GetBytes("HelloWorld");
- byte[] cipherText = EncryptDataUsingAED(plainText, CertFixture.cek, CColumnEncryptionType.Deterministic);
+ byte[] cipherText = EncryptDataUsingAED(plainText, _cek, CColumnEncryptionType.Deterministic);
Exception decryptEx = Assert.Throws(() => DecryptWithKey(plainText, cipherMD));
Assert.Matches(expectedMessage, decryptEx.InnerException.Message);
@@ -157,9 +177,9 @@ public void TestUnknownCustomKeyStoreProvider()
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_UnrecognizedKeyStoreProviderName,
invalidProviderName, "'MSSQL_CERTIFICATE_STORE', 'MSSQL_CNG_STORE', 'MSSQL_CSP_PROVIDER'", "");
Object cipherMD = GetSqlCipherMetadata(0, 1, null, 1, 0x03);
- AddEncryptionKeyToCipherMD(cipherMD, CertFixture.encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, CertFixture.certificatePath, invalidProviderName, "RSA_OAEP");
+ AddEncryptionKeyToCipherMD(cipherMD, _encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, _certificatePath, invalidProviderName, "RSA_OAEP");
byte[] plainText = Encoding.Unicode.GetBytes("HelloWorld");
- byte[] cipherText = EncryptDataUsingAED(plainText, CertFixture.cek, CColumnEncryptionType.Deterministic);
+ byte[] cipherText = EncryptDataUsingAED(plainText, _cek, CColumnEncryptionType.Deterministic);
Exception decryptEx = Assert.Throws(() => DecryptWithKey(plainText, cipherMD));
Assert.Contains(expectedMessage, decryptEx.InnerException.Message);
@@ -179,9 +199,9 @@ public void TestTceUnknownEncryptionAlgorithm()
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_UnknownColumnEncryptionAlgorithm,
unknownEncryptionAlgorithm, "'AEAD_AES_256_CBC_HMAC_SHA256'");
Object cipherMD = GetSqlCipherMetadata(0, 0, "Dummy", 1, 0x01);
- AddEncryptionKeyToCipherMD(cipherMD, CertFixture.encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, CertFixture.certificatePath, "MSSQL_CERTIFICATE_STORE", "RSA_OAEP");
+ AddEncryptionKeyToCipherMD(cipherMD, _encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, _certificatePath, "MSSQL_CERTIFICATE_STORE", "RSA_OAEP");
byte[] plainText = Encoding.Unicode.GetBytes("HelloWorld");
- byte[] cipherText = EncryptDataUsingAED(plainText, CertFixture.cek, CColumnEncryptionType.Deterministic);
+ byte[] cipherText = EncryptDataUsingAED(plainText, _cek, CColumnEncryptionType.Deterministic);
Exception decryptEx = Assert.Throws(() => DecryptWithKey(cipherText, cipherMD));
Assert.Contains(expectedMessage, decryptEx.InnerException.Message);
@@ -194,15 +214,15 @@ public void TestTceUnknownEncryptionAlgorithm()
[PlatformSpecific(TestPlatforms.Windows)]
public void TestExceptionsFromCertStore()
{
- byte[] corruptedCek = GenerateInvalidEncryptedCek(CertFixture.cek, ECEKCorruption.SIGNATURE);
+ byte[] corruptedCek = GenerateInvalidEncryptedCek(_cek, ECEKCorruption.SIGNATURE);
string expectedMessage = string.Format(SystemDataResourceManager.Instance.TCE_KeyDecryptionFailedCertStore,
"MSSQL_CERTIFICATE_STORE", BitConverter.ToString(corruptedCek, corruptedCek.Length - 10, 10));
Object cipherMD = GetSqlCipherMetadata(0, 1, null, 1, 0x01);
- AddEncryptionKeyToCipherMD(cipherMD, corruptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, CertFixture.certificatePath, "MSSQL_CERTIFICATE_STORE", "RSA_OAEP");
+ AddEncryptionKeyToCipherMD(cipherMD, corruptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, _certificatePath, "MSSQL_CERTIFICATE_STORE", "RSA_OAEP");
byte[] plainText = Encoding.Unicode.GetBytes("HelloWorld");
- byte[] cipherText = EncryptDataUsingAED(plainText, CertFixture.cek, CColumnEncryptionType.Deterministic);
+ byte[] cipherText = EncryptDataUsingAED(plainText, _cek, CColumnEncryptionType.Deterministic);
Exception decryptEx = Assert.Throws(() => DecryptWithKey(cipherText, cipherMD));
Assert.Matches(expectedMessage, decryptEx.InnerException.Message);
@@ -224,9 +244,9 @@ public void TestExceptionsFromCustomKeyStore()
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders);
object cipherMD = GetSqlCipherMetadata(0, 1, null, 1, 0x01);
- AddEncryptionKeyToCipherMD(cipherMD, CertFixture.encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, CertFixture.certificatePath, "DummyProvider", "DummyAlgo");
+ AddEncryptionKeyToCipherMD(cipherMD, _encryptedCek, 0, 0, 0, new byte[] { 0x01, 0x02, 0x03 }, _certificatePath, "DummyProvider", "DummyAlgo");
byte[] plainText = Encoding.Unicode.GetBytes("HelloWorld");
- byte[] cipherText = EncryptDataUsingAED(plainText, CertFixture.cek, CColumnEncryptionType.Deterministic);
+ byte[] cipherText = EncryptDataUsingAED(plainText, _cek, CColumnEncryptionType.Deterministic);
Exception decryptEx = Assert.Throws(() => DecryptWithKey(cipherText, cipherMD));
Assert.Contains(expectedMessage, decryptEx.InnerException.Message);
@@ -238,35 +258,4 @@ public void TestExceptionsFromCustomKeyStore()
}
}
}
-
- public class CertFixture : IDisposable
- {
- private readonly SqlColumnEncryptionCertificateStoreProvider provider = new SqlColumnEncryptionCertificateStoreProvider();
-
- public static X509Certificate2 certificate;
- public static string thumbprint;
- public static string certificatePath;
- public static byte[] cek;
- public static byte[] encryptedCek;
-
- public CertFixture()
- {
- if (certificate == null)
- {
- certificate = Utility.CreateCertificate();
- }
- thumbprint = certificate.Thumbprint;
- certificatePath = string.Format("CurrentUser/My/{0}", thumbprint);
- cek = GenerateRandomBytes(32);
- encryptedCek = provider.EncryptColumnEncryptionKey(certificatePath, "RSA_OAEP", cek);
-
- // Disable the cache to avoid false failures.
- SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled = false;
- }
-
- public void Dispose()
- {
- // Do NOT remove certificate for concurrent consistency. Certificates are used for other test cases as well.
- }
- }
}
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ExceptionsCertStore.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ExceptionsCertStore.cs
deleted file mode 100644
index 30f4528d23..0000000000
--- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ExceptionsCertStore.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Security.Cryptography.X509Certificates;
-using Xunit;
-
-namespace Microsoft.Data.SqlClient.Tests.AlwaysEncryptedTests
-{
- public class ExceptionsCertStore : IClassFixture
- {
- private readonly string masterKeyEncAlgo = "RSA_OAEP";
-
- [Fact]
- [PlatformSpecific(TestPlatforms.Windows)]
- public void EmptyCertificateThumbprint()
- {
- string dummyPath = string.Format("CurrentUser/My/");
- string expectedMessage = string.Format(@"Empty certificate thumbprint specified in certificate path '{0}'.\s+\(?Parameter (name: )?'?masterKeyPath('\))?", dummyPath);
-
- ArgumentException e = Assert.Throws(() => ExceptionCertFixture.certStoreProvider.EncryptColumnEncryptionKey(dummyPath, masterKeyEncAlgo, ExceptionCertFixture.encryptedCek));
- Assert.Matches(expectedMessage, e.Message);
-
- expectedMessage = string.Format(@"Internal error. Empty certificate thumbprint specified in certificate path '{0}'.\s+\(?Parameter (name: )?'?masterKeyPath('\))?", dummyPath);
- e = Assert.Throws(() => ExceptionCertFixture.certStoreProvider.DecryptColumnEncryptionKey(dummyPath, masterKeyEncAlgo, ExceptionCertFixture.encryptedCek));
- Assert.Matches(expectedMessage, e.Message);
- }
-
- [Fact]
- [PlatformSpecific(TestPlatforms.Windows)]
- public void CertificateNotFound()
- {
- string dummyPath = string.Format("CurrentUser/My/JunkThumbprint");
- string expectedMessage = string.Format(@"Certificate with thumbprint 'JunkThumbprint' not found in certificate store 'My' in certificate location 'CurrentUser'.\s+\(?Parameter (name: )?'?masterKeyPath('\))?");
- ArgumentException e = Assert.Throws(() => ExceptionCertFixture.certStoreProvider.EncryptColumnEncryptionKey(dummyPath, masterKeyEncAlgo, ExceptionCertFixture.encryptedCek));
- Assert.Matches(expectedMessage, e.Message);
-
- expectedMessage = string.Format(@"Certificate with thumbprint 'JunkThumbprint' not found in certificate store 'My' in certificate location 'CurrentUser'. Verify the certificate path in the column master key definition in the database is correct, and the certificate has been imported correctly into the certificate location/store.\s+\(?Parameter (name: )?'?masterKeyPath('\))?");
- e = Assert.Throws(() => ExceptionCertFixture.certStoreProvider.DecryptColumnEncryptionKey(dummyPath, masterKeyEncAlgo, ExceptionCertFixture.encryptedCek));
- Assert.Matches(expectedMessage, e.Message);
- }
-
-#if NETFRAMEWORK
- [Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.Netcoreapp)]
- public void CertificateWithNoPrivateKey()
- {
- string expectedMessage = string.Format("Certificate specified in key path '{0}' does not have a private key to encrypt a column encryption key. Verify the certificate is imported correctly.\r\nParameter name: masterKeyPath", ExceptionCertFixture.masterKeyPathNPK);
- ArgumentException e = Assert.Throws(() =>
- ExceptionCertFixture.certStoreProvider.EncryptColumnEncryptionKey(
- ExceptionCertFixture.masterKeyPathNPK, masterKeyEncAlgo, ExceptionCertFixture.encryptedCek));
- Assert.Contains(expectedMessage, e.Message);
-
- expectedMessage = string.Format("Certificate specified in key path '{0}' does not have a private key to decrypt a column encryption key. Verify the certificate is imported correctly.\r\nParameter name: masterKeyPath", ExceptionCertFixture.masterKeyPathNPK);
- e = Assert.Throws(() =>
- ExceptionCertFixture.certStoreProvider.DecryptColumnEncryptionKey(
- ExceptionCertFixture.masterKeyPathNPK, masterKeyEncAlgo, ExceptionCertFixture.encryptedCek));
- Assert.Contains(expectedMessage, e.Message);
- }
-#endif
- }
- public class ExceptionCertFixture : IDisposable
- {
- public static readonly SqlColumnEncryptionCertificateStoreProvider certStoreProvider = new SqlColumnEncryptionCertificateStoreProvider();
- public static X509Certificate2 certificate;
- public static string certificatePath;
- public static string thumbprint;
- public static byte[] cek;
- public static byte[] encryptedCek;
-#if NETFRAMEWORK
- public static X509Certificate2 masterKeyCertificateNPK; // no private key
- public static string thumbprintNPK; // No private key
- public static string masterKeyPathNPK;
-#endif
-
- public ExceptionCertFixture()
- {
- if(certificate == null)
- {
- certificate = Utility.CreateCertificate();
- }
- thumbprint = certificate.Thumbprint;
- certificatePath = string.Format("CurrentUser/My/{0}", thumbprint);
- cek = Utility.GenerateRandomBytes(32);
- encryptedCek = certStoreProvider.EncryptColumnEncryptionKey(certificatePath, "RSA_OAEP", cek);
-#if NETFRAMEWORK
- if (masterKeyCertificateNPK == null)
- {
- masterKeyCertificateNPK = Utility.CreateCertificateWithNoPrivateKey();
- }
- thumbprintNPK = masterKeyCertificateNPK.Thumbprint;
- masterKeyPathNPK = "CurrentUser/My/" + thumbprintNPK;
-#endif
- // Disable the cache to avoid false failures.
- SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled = false;
- }
-
- public void Dispose()
- {
- // Do NOT remove certificate for concurrent consistency. Certificates are used for other test cases as well.
- }
- }
-}
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCertificateStoreProviderShould.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCertificateStoreProviderShould.cs
index c6107a1852..3a220cd9c7 100644
--- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCertificateStoreProviderShould.cs
+++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCertificateStoreProviderShould.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using Microsoft.Data.SqlClient.TestUtilities.Fixtures;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -16,9 +17,10 @@
namespace Microsoft.Data.SqlClient.Tests.AlwaysEncryptedTests
{
- public class SqlColumnEncryptionCertificateStoreProviderWindowsShould : IClassFixture
+ public class SqlColumnEncryptionCertificateStoreProviderWindowsShould : IClassFixture
{
- private const string MASTER_KEY_PATH = "CurrentUser/My/C74D53B816A971E3FF9714FE1DD2E57E1710D946";
+ private const string PRIMARY_CERTIFICATE_PATH = "CurrentUser/My/{primary_thumbprint}";
+ private const string SECONDARY_CERTIFICATE_PATH = "CurrentUser/My/{secondary_thumbprint}";
private const string ENCRYPTION_ALGORITHM = "RSA_OAEP";
///
@@ -93,14 +95,25 @@ public class SqlColumnEncryptionCertificateStoreProviderWindowsShould : IClassFi
///
private const int CipherTextStartIndex = IVStartIndex + IVLengthInBytes;
+ private readonly ColumnEncryptionCertificateFixture _certFixture;
+
+ public SqlColumnEncryptionCertificateStoreProviderWindowsShould(ColumnEncryptionCertificateFixture certFixture)
+ {
+ _certFixture = certFixture;
+
+ // Disable the cache to avoid false failures.
+ SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled = false;
+ }
+
[Theory]
[InvalidDecryptionParameters]
[PlatformSpecific(TestPlatforms.Windows)]
public void ThrowExceptionWithInvalidParameterWhileDecryptingColumnEncryptionKey(string errorMsg, Type exceptionType, string masterKeyPath, string encryptionAlgorithm, byte[] bytes)
{
var provider = new SqlColumnEncryptionCertificateStoreProvider();
- Exception ex = Assert.Throws(exceptionType, () => provider.DecryptColumnEncryptionKey(masterKeyPath, encryptionAlgorithm, bytes));
- Assert.Matches(errorMsg, ex.Message);
+ Exception ex = Assert.Throws(exceptionType,
+ () => provider.DecryptColumnEncryptionKey(ReplaceKeyTokens(masterKeyPath), encryptionAlgorithm, bytes));
+ Assert.Matches(ReplaceKeyTokens(errorMsg), ex.Message);
}
[Theory]
@@ -109,8 +122,8 @@ public void ThrowExceptionWithInvalidParameterWhileDecryptingColumnEncryptionKey
public void ThrowExceptionWithInvalidParameterWhileEncryptingColumnEncryptionKey(string errorMsg, Type exceptionType, string masterKeyPath, string encryptionAlgorithm, byte[] bytes)
{
var provider = new SqlColumnEncryptionCertificateStoreProvider();
- Exception ex = Assert.Throws(exceptionType, () => provider.EncryptColumnEncryptionKey(masterKeyPath, encryptionAlgorithm, bytes));
- Assert.Matches(errorMsg, ex.Message);
+ Exception ex = Assert.Throws(exceptionType, () => provider.EncryptColumnEncryptionKey(ReplaceKeyTokens(masterKeyPath), encryptionAlgorithm, bytes));
+ Assert.Matches(ReplaceKeyTokens(errorMsg), ex.Message);
}
[Theory]
@@ -124,26 +137,26 @@ public void ThrowExceptionWithInvalidParameterWhileSigningColumnMasterKeyMetadat
}
[Theory]
- [InlineData("CurrentUser/My/C74D53B816A971E3FF9714FE1DD2E57E1710D946")]
- [InlineData("CURRENTUSER/My/C74D53B816A971E3FF9714FE1DD2E57E1710D946")]
- [InlineData("currentuser/My/C74D53B816A971E3FF9714FE1DD2E57E1710D946")]
+ [InlineData("CurrentUser/My/{primary_thumbprint}")]
+ [InlineData("CURRENTUSER/My/{primary_thumbprint}")]
+ [InlineData("currentuser/My/{primary_thumbprint}")]
[PlatformSpecific(TestPlatforms.Windows)]
- public void SetStoreLocationApproperiatelyFromMasterKeyPathRegardlessOfCase(string masterKeyPath)
+ public void SetStoreLocationAppropriatelyFromMasterKeyPathRegardlessOfCase(string masterKeyPath)
{
var provider = new SqlColumnEncryptionCertificateStoreProvider();
- byte[] ciphertext = provider.EncryptColumnEncryptionKey(masterKeyPath, ENCRYPTION_ALGORITHM, new byte[] { 1, 2, 3, 4, 5 });
+ byte[] ciphertext = provider.EncryptColumnEncryptionKey(ReplaceKeyTokens(masterKeyPath), ENCRYPTION_ALGORITHM, new byte[] { 1, 2, 3, 4, 5 });
Assert.NotNull(ciphertext);
}
[Theory]
- [InlineData("CurrentUser/my/C74D53B816A971E3FF9714FE1DD2E57E1710D946")]
- [InlineData("CurrentUser/MY/C74D53B816A971E3FF9714FE1DD2E57E1710D946")]
- [InlineData("CurrentUser/My/C74D53B816A971E3FF9714FE1DD2E57E1710D946")]
+ [InlineData("CurrentUser/my/{primary_thumbprint}")]
+ [InlineData("CurrentUser/MY/{primary_thumbprint}")]
+ [InlineData("CurrentUser/My/{primary_thumbprint}")]
[PlatformSpecific(TestPlatforms.Windows)]
- public void SetStoreNameApproperiatelyFromMasterKeyPathRegardlessOfCase(string masterKeyPath)
+ public void SetStoreNameAppropriatelyFromMasterKeyPathRegardlessOfCase(string masterKeyPath)
{
var provider = new SqlColumnEncryptionCertificateStoreProvider();
- byte[] ciphertext = provider.EncryptColumnEncryptionKey(masterKeyPath, ENCRYPTION_ALGORITHM, new byte[] { 1, 2, 3, 4, 5 });
+ byte[] ciphertext = provider.EncryptColumnEncryptionKey(ReplaceKeyTokens(masterKeyPath), ENCRYPTION_ALGORITHM, new byte[] { 1, 2, 3, 4, 5 });
Assert.NotNull(ciphertext);
}
@@ -155,7 +168,7 @@ public void SetStoreNameApproperiatelyFromMasterKeyPathRegardlessOfCase(string m
public void AcceptEncryptionAlgorithmRegardlessOfCase(string algorithm)
{
var provider = new SqlColumnEncryptionCertificateStoreProvider();
- byte[] ciphertext = provider.EncryptColumnEncryptionKey(MASTER_KEY_PATH, algorithm, new byte[] { 1, 2, 3, 4, 5 });
+ byte[] ciphertext = provider.EncryptColumnEncryptionKey(ReplaceKeyTokens(PRIMARY_CERTIFICATE_PATH), algorithm, new byte[] { 1, 2, 3, 4, 5 });
Assert.NotNull(ciphertext);
}
@@ -171,8 +184,8 @@ public void EncryptKeyAndThenDecryptItSuccessfully(int dataSize)
var randomNumberGenerator = new Random();
randomNumberGenerator.NextBytes(columnEncryptionKey);
- byte[] encryptedData = provider.EncryptColumnEncryptionKey(MASTER_KEY_PATH, ENCRYPTION_ALGORITHM, columnEncryptionKey);
- byte[] decryptedData = provider.DecryptColumnEncryptionKey(MASTER_KEY_PATH, ENCRYPTION_ALGORITHM, encryptedData);
+ byte[] encryptedData = provider.EncryptColumnEncryptionKey(ReplaceKeyTokens(PRIMARY_CERTIFICATE_PATH), ENCRYPTION_ALGORITHM, columnEncryptionKey);
+ byte[] decryptedData = provider.DecryptColumnEncryptionKey(ReplaceKeyTokens(PRIMARY_CERTIFICATE_PATH), ENCRYPTION_ALGORITHM, encryptedData);
Assert.Equal(columnEncryptionKey, decryptedData);
}
@@ -183,10 +196,10 @@ public void EncryptKeyAndThenDecryptItSuccessfully(int dataSize)
public void SignAndVerifyColumnMasterKeyMetadataSuccessfully(bool allowEnclaveComputations)
{
var provider = new SqlColumnEncryptionCertificateStoreProvider();
- byte[] signature = provider.SignColumnMasterKeyMetadata(MASTER_KEY_PATH, allowEnclaveComputations);
+ byte[] signature = provider.SignColumnMasterKeyMetadata(ReplaceKeyTokens(PRIMARY_CERTIFICATE_PATH), allowEnclaveComputations);
Assert.NotNull(signature);
- Assert.True(provider.VerifyColumnMasterKeyMetadata(MASTER_KEY_PATH, allowEnclaveComputations, signature));
- Assert.False(provider.VerifyColumnMasterKeyMetadata(MASTER_KEY_PATH, !allowEnclaveComputations, signature));
+ Assert.True(provider.VerifyColumnMasterKeyMetadata(ReplaceKeyTokens(PRIMARY_CERTIFICATE_PATH), allowEnclaveComputations, signature));
+ Assert.False(provider.VerifyColumnMasterKeyMetadata(ReplaceKeyTokens(PRIMARY_CERTIFICATE_PATH), !allowEnclaveComputations, signature));
}
[Theory]
@@ -197,10 +210,10 @@ public void FailToVerifyColumnMasterKeyMetadataWithWrongCertificate(bool allowEn
{
var provider = new SqlColumnEncryptionCertificateStoreProvider();
- byte[] signature = provider.SignColumnMasterKeyMetadata(MASTER_KEY_PATH, allowEnclaveComputations);
+ byte[] signature = provider.SignColumnMasterKeyMetadata(ReplaceKeyTokens(PRIMARY_CERTIFICATE_PATH), allowEnclaveComputations);
Assert.NotNull(signature);
Assert.False(
- provider.VerifyColumnMasterKeyMetadata("CurrentUser/My/4281446463C6F7F5B8EDFFA4BD6E345E46857CAD", allowEnclaveComputations, signature));
+ provider.VerifyColumnMasterKeyMetadata(ReplaceKeyTokens(SECONDARY_CERTIFICATE_PATH), allowEnclaveComputations, signature));
}
[Fact]
@@ -209,10 +222,10 @@ public void EncryptAndDecryptDataSuccessfully()
{
var input = new byte[] { 1, 2, 3, 4, 5 };
var provider = new SqlColumnEncryptionCertificateStoreProvider();
- byte[] ciphertext = provider.EncryptColumnEncryptionKey(MASTER_KEY_PATH, ENCRYPTION_ALGORITHM,
+ byte[] ciphertext = provider.EncryptColumnEncryptionKey(ReplaceKeyTokens(PRIMARY_CERTIFICATE_PATH), ENCRYPTION_ALGORITHM,
new byte[] { 1, 2, 3, 4, 5 });
byte[] output =
- provider.DecryptColumnEncryptionKey(MASTER_KEY_PATH, ENCRYPTION_ALGORITHM, ciphertext);
+ provider.DecryptColumnEncryptionKey(ReplaceKeyTokens(PRIMARY_CERTIFICATE_PATH), ENCRYPTION_ALGORITHM, ciphertext);
Assert.Equal(input, output);
}
@@ -222,11 +235,9 @@ public void EncryptAndDecryptDataSuccessfully()
public void TestCEKEncryptionReversal(StoreLocation certificateStoreLocation, String certificateStoreNameAndLocation)
{
Assert.True(!string.IsNullOrWhiteSpace(certificateStoreNameAndLocation));
- string certificateName = @"TestCertificate12";
// Fetch the newly created cert.
- X509Certificate2 masterKeyCertificate = Utility.GetCertificate(certificateName,
- certificateStoreLocation);
+ X509Certificate2 masterKeyCertificate = _certFixture.GetCertificate(certificateStoreLocation);
Assert.True(masterKeyCertificate != null);
@@ -389,11 +400,8 @@ public void TestValidCertificatePaths(string certificateStoreNameAndLocation, ob
certificateStoreLocation = StoreLocation.CurrentUser;
}
- string certificateName = @"TestCertificate12";
-
// Fetch the newly created cert.
- X509Certificate2 masterKeyCertificate = Utility.GetCertificate(certificateName,
- certificateStoreLocation);
+ X509Certificate2 masterKeyCertificate = _certFixture.GetCertificate(certificateStoreLocation);
Assert.True(masterKeyCertificate != null);
@@ -459,6 +467,13 @@ public void TestEncryptedCellValueTampering(string parameterToTamper, Utility.CC
Assert.Matches(expectedErrorMessage, e.InnerException.Message);
}
+ private string ReplaceKeyTokens(string keyPath)
+ {
+ return keyPath?.Replace("{primary_thumbprint}", _certFixture.PrimaryColumnEncryptionCertificate.Thumbprint)
+ ?.Replace("{secondary_thumbprint}", _certFixture.SecondaryColumnEncryptionCertificate.Thumbprint)
+ ?.Replace("{npk_thumbprint}", _certFixture.CertificateWithoutPrivateKey.Thumbprint);
+ }
+
public class AeadEncryptionParameters : DataAttribute
{
///
@@ -496,7 +511,7 @@ public override IEnumerable