Skip to content

Tests | Remove hardcoded certificates from functional tests #3034

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Dec 2, 2024
Merged
1 change: 1 addition & 0 deletions build.proj
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
<FunctionalTests Include="**/tools/TDS/TDS/TDS.csproj" />
<FunctionalTests Include="**/tools/TDS/TDS.EndPoint/TDS.EndPoint.csproj" />
<FunctionalTests Include="**/tools/TDS/TDS.Servers/TDS.Servers.csproj" />
<FunctionalTests Include="**/tools/Microsoft.Data.SqlClient.TestUtilities/Microsoft.Data.SqlClient.TestUtilities.csproj"/>
<FunctionalTests Include="**/tools/CoreFx.Private.TestUtilities/CoreFx.Private.TestUtilities.csproj" />
<FunctionalTests Include="**/ManualTests/SQL/UdtTest/UDTs/Address/Address.csproj" />
<FunctionalTests Include="**/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj" />
Expand Down Expand Up @@ -187,7 +188,7 @@

<Target Name="RunManualTests">
<!-- Windows -->
<Exec ConsoleToMsBuild="true" Command="$(DotnetPath)dotnet test &quot;@(ManualTestsProj)&quot; -p:Configuration=$(Configuration) -p:Target$(TFGroup)Version=$(TF) -p:ReferenceType=$(ReferenceType) --no-build -l &quot;console;verbosity=normal&quot; --collect &quot;Code coverage&quot; -p:TestSet=$(TestSet) --results-directory $(ResultsDirectory) -p:TestTargetOS=Windows$(TargetGroup) --filter &quot;category!=non$(TargetGroup)tests&amp;category!=failing&amp;category!=nonwindowstests&quot; &quot;--logger:trx;LogFilePrefix=Manual-Windows$(TargetGroup)-$(TestSet)&quot;" Condition="'$(IsEnabledWindows)' == 'true'"/>

Check failure on line 191 in build.proj

View check run for this annotation

Azure Pipelines / CI-SqlClient (Win22_Sql22_named_instance net8_0_AnyCPU_ManagedSNI_3)

build.proj#L191

build.proj(191,5): Error MSB3073: The command "dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration=Release -p:TargetnetcoreVersion=net8.0 -p:ReferenceType=Project --no-build -l "console;verbosity=normal" --collect "Code coverage" -p:TestSet=3 --results-directory TestResults -p:TestTargetOS=Windowsnetcoreapp --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" "--logger:trx;LogFilePrefix=Manual-Windowsnetcoreapp-3"" exited with code 1.

Check failure on line 191 in build.proj

View check run for this annotation

Azure Pipelines / CI-SqlClient

build.proj#L191

build.proj(191,5): Error MSB3073: The command "dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration=Release -p:TargetnetcoreVersion=net8.0 -p:ReferenceType=Project --no-build -l "console;verbosity=normal" --collect "Code coverage" -p:TestSet=3 --results-directory TestResults -p:TestTargetOS=Windowsnetcoreapp --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" "--logger:trx;LogFilePrefix=Manual-Windowsnetcoreapp-3"" exited with code 1.
<!-- Unix -->
<Exec ConsoleToMsBuild="true" Command="$(DotnetPath)dotnet test &quot;@(ManualTestsProj)&quot; -p:Configuration=$(Configuration) -p:TargetNetCoreVersion=$(TF) -p:ReferenceType=$(ReferenceType) --no-build -l &quot;console;verbosity=normal&quot; --collect &quot;Code coverage&quot; -p:TestSet=$(TestSet) --results-directory $(ResultsDirectory) -p:TestTargetOS=Unixnetcoreapp --filter &quot;category!=nonnetcoreapptests&amp;category!=failing&amp;category!=nonlinuxtests&amp;category!=nonuaptests&quot; &quot;--logger:trx;LogFilePrefix=Manual-Unixnetcoreapp-$(TestSet)&quot;" Condition="'$(IsEnabledWindows)' != 'true'"/>
</Target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<CertFixture>
public class ExceptionsAlgorithmErrors : IClassFixture<ColumnEncryptionCertificateFixture>
{
// 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()
Expand Down Expand Up @@ -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'");
Expand All @@ -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<TargetInvocationException>(() => DecryptDataUsingAED(cipherText, CertFixture.cek, CColumnEncryptionType.Deterministic));
TargetInvocationException e = Assert.Throws<TargetInvocationException>(() => DecryptDataUsingAED(cipherText, _cek, CColumnEncryptionType.Deterministic));
Assert.Contains(expectedMessage, e.InnerException.Message);
}

Expand All @@ -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<TargetInvocationException>(() => DecryptDataUsingAED(cipherText, CertFixture.cek, CColumnEncryptionType.Deterministic));
TargetInvocationException e = Assert.Throws<TargetInvocationException>(() => DecryptDataUsingAED(cipherText, _cek, CColumnEncryptionType.Deterministic));
Assert.Contains(expectedMessage, e.InnerException.Message);
}

Expand All @@ -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<TargetInvocationException>(() => DecryptDataUsingAED(cipherText, CertFixture.cek, CColumnEncryptionType.Deterministic));
TargetInvocationException e = Assert.Throws<TargetInvocationException>(() => DecryptDataUsingAED(cipherText, _cek, CColumnEncryptionType.Deterministic));
Assert.Contains(expectedMessage, e.InnerException.Message);
}

Expand All @@ -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<TargetInvocationException>(() => DecryptWithKey(cipherText, cipherMD));
Assert.Contains(expectedMessage, e.InnerException.Message);
Expand All @@ -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<TargetInvocationException>(() => DecryptWithKey(plainText, cipherMD));
Assert.Matches(expectedMessage, decryptEx.InnerException.Message);
Expand All @@ -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<TargetInvocationException>(() => DecryptWithKey(plainText, cipherMD));
Assert.Contains(expectedMessage, decryptEx.InnerException.Message);
Expand All @@ -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<TargetInvocationException>(() => DecryptWithKey(cipherText, cipherMD));
Assert.Contains(expectedMessage, decryptEx.InnerException.Message);
Expand All @@ -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<TargetInvocationException>(() => DecryptWithKey(cipherText, cipherMD));
Assert.Matches(expectedMessage, decryptEx.InnerException.Message);
Expand All @@ -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<TargetInvocationException>(() => DecryptWithKey(cipherText, cipherMD));
Assert.Contains(expectedMessage, decryptEx.InnerException.Message);
Expand All @@ -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.
}
}
}
Loading
Loading