Skip to content
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

Update tests #4

Merged
merged 2 commits into from
Feb 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ internal static class Constants
@"vault.azure.net", // default
@"vault.azure.cn", // Azure China
@"vault.usgovcloudapi.net", // US Government
@"vault.microsoftazure.de" // Azure Germany
@"vault.microsoftazure.de", // Azure Germany
@"managedhsm.azure.net", // public HSM vault
@"managedhsm.azure.cn", // Azure China HSM vault
@"managedhsm.usgovcloudapi.net", // US Government HSM vault
@"managedhsm.microsoftazure.de" // Azure Germany HSM vault
};

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,16 @@ public SqlColumnEncryptionAzureKeyVaultProvider(TokenCredential tokenCredential,
/// and an array of trusted endpoints.
/// </summary>
/// <param name="tokenCredential">Instance of an implementation of Token Credential that is capable of providing an OAuth Token</param>
/// <param name="trustedEndPoints">TrustedEndpoints are used to validate the master key path</param>
public SqlColumnEncryptionAzureKeyVaultProvider(TokenCredential tokenCredential, string[] trustedEndPoints)
/// <param name="trustedEndpoints">TrustedEndpoints are used to validate the master key path</param>
public SqlColumnEncryptionAzureKeyVaultProvider(TokenCredential tokenCredential, string[] trustedEndpoints)
{
ValidateNotNull(tokenCredential, nameof(tokenCredential));
ValidateNotNull(trustedEndPoints, nameof(trustedEndPoints));
ValidateNotEmpty(trustedEndPoints, nameof(trustedEndPoints));
ValidateNotNullOrWhitespaceForEach(trustedEndPoints, nameof(trustedEndPoints));
ValidateNotNull(trustedEndpoints, nameof(trustedEndpoints));
ValidateNotEmpty(trustedEndpoints, nameof(trustedEndpoints));
ValidateNotNullOrWhitespaceForEach(trustedEndpoints, nameof(trustedEndpoints));

KeyCryptographer = new AzureSqlKeyCryptographer(tokenCredential);
TrustedEndPoints = trustedEndPoints;
TrustedEndPoints = trustedEndpoints;
}
#endregion

Expand Down Expand Up @@ -242,7 +242,6 @@ public override byte[] EncryptColumnEncryptionKey(string masterKeyPath, string e
{
// Validate the input parameters
ValidateNonEmptyAKVPath(masterKeyPath, isSystemOp: true);
ValidateNotNullOrWhitespace(encryptionAlgorithm, nameof(encryptionAlgorithm));
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ValidateEncryptionAlgorithm() already validates if encryptionAlgorithm is null or not equal to "RSA_OAEP".

ValidateEncryptionAlgorithm(encryptionAlgorithm, isSystemOp: true);
ValidateNotNull(columnEncryptionKey, nameof(columnEncryptionKey));
ValidateNotEmpty(columnEncryptionKey, nameof(columnEncryptionKey));
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="InvalidTrustedEndpointTemplate" xml:space="preserve">
<value>Invalid trusted endpoint specified: '{0}'; a trusted endpoint must have a value.</value>
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A null or empty endpoint couldn't be interpolated.

<data name="NullOrWhitespaceForEach" xml:space="preserve">
<value>One or more of the elements in {0} are null or empty or consist of only whitespace.</value>
</data>
<data name="CipherTextLengthMismatch" xml:space="preserve">
<value>CipherText length does not match the RSA key size.</value>
Expand Down Expand Up @@ -174,4 +174,4 @@
<data name="NullAlgorithmInternal" xml:space="preserve">
<value>Internal error. Key encryption algorithm cannot be null.</value>
</data>
</root>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,23 @@ internal static void ValidateNotNullOrWhitespace(string parameter, string name)
{
if (string.IsNullOrWhiteSpace(parameter))
{
throw new ArgumentException(name, Strings.NullOrWhitespaceArgument);
throw new ArgumentException(string.Format(Strings.NullOrWhitespaceArgument, name));
}
}

internal static void ValidateNotEmpty(IList parameter, string name)
{
if (parameter.Count == 0)
{
throw new ArgumentException(name, Strings.EmptyArgumentInternal);
throw new ArgumentException(string.Format(Strings.EmptyArgumentInternal, name));
}
}

internal static void ValidateNotNullOrWhitespaceForEach(string[] parameters, string name)
{
foreach (var parameter in parameters)
if (parameters.Any(s => string.IsNullOrWhiteSpace(s)))
{
if (null == parameter)
{
throw new ArgumentException(parameter, Strings.InvalidTrustedEndpointTemplate);
}
throw new ArgumentException(string.Format(Strings.NullOrWhitespaceForEach, name));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System;
using System.Security.Cryptography;
using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider;
using Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup;
using Xunit;

Expand Down Expand Up @@ -45,36 +46,36 @@ public void NullEncryptionAlgorithm()
Exception ex1 = Assert.Throws<ArgumentNullException>(() => fixture.AkvStoreProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, null, cek));
Assert.Matches($@"Internal error. Key encryption algorithm cannot be null.\s+\(?Parameter (name: )?'?encryptionAlgorithm('\))?", ex1.Message);
Exception ex2 = Assert.Throws<ArgumentNullException>(() => fixture.AkvStoreProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, null, cek));
Assert.Matches($@"Key encryption algorithm cannot be null.\s+\(?Parameter (name: )?'?encryptionAlgorithm('\))?", ex2.Message);
Assert.Matches($@"Internal error. Key encryption algorithm cannot be null.\s+\(?Parameter (name: )?'?encryptionAlgorithm('\))?", ex2.Message);
}


[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAKVSetupAvailable))]
public void EmptyColumnEncryptionKey()
{
Exception ex1 = Assert.Throws<ArgumentException>(() => fixture.AkvStoreProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, MasterKeyEncAlgo, new byte[] { }));
Assert.Matches($@"Empty column encryption key specified.\s+\(?Parameter (name: )?'?columnEncryptionKey('\))?", ex1.Message);
Assert.Matches($@"Internal error. Empty columnEncryptionKey specified.", ex1.Message);
}

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAKVSetupAvailable))]
public void NullColumnEncryptionKey()
{
Exception ex1 = Assert.Throws<ArgumentNullException>(() => fixture.AkvStoreProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, MasterKeyEncAlgo, null));
Assert.Matches($@"Column encryption key cannot be null.\s+\(?Parameter (name: )?'?columnEncryptionKey('\))?", ex1.Message);
Assert.Matches($@"Value cannot be null..\s+\(?Parameter (name: )?'?columnEncryptionKey('\))?", ex1.Message);
}

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAKVSetupAvailable))]
public void EmptyEncryptedColumnEncryptionKey()
{
Exception ex1 = Assert.Throws<ArgumentException>(() => fixture.AkvStoreProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, MasterKeyEncAlgo, new byte[] { }));
Assert.Matches($@"Internal error. Empty encrypted column encryption key specified.\s+\(?Parameter (name: )?'?encryptedColumnEncryptionKey('\))?", ex1.Message);
Assert.Matches($@"Internal error. Empty encryptedColumnEncryptionKey specified", ex1.Message);
}

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAKVSetupAvailable))]
public void NullEncryptedColumnEncryptionKey()
{
Exception ex1 = Assert.Throws<ArgumentNullException>(() => fixture.AkvStoreProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, MasterKeyEncAlgo, null));
Assert.Matches($@"Internal error. Encrypted column encryption key cannot be null.\s+\(?Parameter (name: )?'?encryptedColumnEncryptionKey('\))?", ex1.Message);
Assert.Matches($@"Value cannot be null.\s+\(?Parameter (name: )?'?encryptedColumnEncryptionKey('\))?", ex1.Message);
}

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAKVSetupAvailable))]
Expand Down Expand Up @@ -152,18 +153,31 @@ public void NullAKVKeyPath()
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAKVSetupAvailable))]
public void InvalidCertificatePath()
{
string dummyPath = @"https://www.microsoft.com";
string errorMessage = $@"Invalid Azure Key Vault key path specified: '{dummyPath}'. Valid trusted endpoints: vault.azure.net, vault.azure.cn, vault.usgovcloudapi.net, vault.microsoftazure.de.\s+\(?Parameter (name: )?'?masterKeyPath('\))?";
string dummyPathWithOnlyHost = @"https://www.microsoft.com";
string invalidUrlErrorMessage = $@"Invalid url specified: '{dummyPathWithOnlyHost}'";
string dummyPathWithInvalidKey = @"https://www.microsoft.vault.azure.com/keys/dummykey/dummykeyid";
string invalidTrustedEndpointErrorMessage = $@"Invalid Azure Key Vault key path specified: '{dummyPathWithInvalidKey}'.
Valid trusted endpoints: vault.azure.net, vault.azure.cn, vault.usgovcloudapi.net, vault.microsoftazure.de, managedhsm.azure.net,
managedhsm.azure.cn, managedhsm.usgovcloudapi.net, managedhsm.microsoftazure.de.\s+\(?Parameter (name: )?'?masterKeyPath('\))?";

Exception ex = Assert.Throws<ArgumentException>(
() => fixture.AkvStoreProvider.EncryptColumnEncryptionKey(dummyPathWithOnlyHost, MasterKeyEncAlgo, cek));
Assert.Matches(invalidUrlErrorMessage, ex.Message);

ex = Assert.Throws<ArgumentException>(
() => fixture.AkvStoreProvider.EncryptColumnEncryptionKey(dummyPathWithInvalidKey, MasterKeyEncAlgo, cek));
Assert.Matches(invalidTrustedEndpointErrorMessage, ex.Message);

ex = Assert.Throws<ArgumentException>(
() => fixture.AkvStoreProvider.DecryptColumnEncryptionKey(dummyPathWithOnlyHost, MasterKeyEncAlgo, encryptedCek));
Assert.Matches(invalidUrlErrorMessage, ex.Message);

Exception ex1 = Assert.Throws<ArgumentException>(() => fixture.AkvStoreProvider.EncryptColumnEncryptionKey(dummyPath, MasterKeyEncAlgo, cek));
Assert.Matches(errorMessage, ex1.Message);

Exception ex2 = Assert.Throws<ArgumentException>(
() => fixture.AkvStoreProvider.DecryptColumnEncryptionKey(dummyPath, MasterKeyEncAlgo, encryptedCek));
Assert.Matches(errorMessage, ex2.Message);
ex = Assert.Throws<ArgumentException>(
() => fixture.AkvStoreProvider.DecryptColumnEncryptionKey(dummyPathWithInvalidKey, MasterKeyEncAlgo, encryptedCek));
Assert.Matches(invalidTrustedEndpointErrorMessage, ex.Message);
}

[InlineData(true)]
[InlineData(true)]
[InlineData(false)]
[ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.IsAKVSetupAvailable))]
public void AkvStoreProviderVerifyFunctionWithInvalidSignature(bool fEnclaveEnabled)
Expand Down Expand Up @@ -206,5 +220,19 @@ public void AkvStoreProviderVerifyFunctionWithInvalidSignature(bool fEnclaveEnab
tamperedCmkSignature[startingByteIndex + randomIndexInCipherText[0]] = cmkSignature[startingByteIndex + randomIndexInCipherText[0]];
}
}

[InlineData(new object[] { new string[] { null } })]
[InlineData(new object[] { new string[] { "" } })]
[InlineData(new object[] { new string[] { " " } })]
[ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.IsAKVSetupAvailable))]
public void InvalidTrustedEndpoints(string[] trustedEndpoints)
{
Exception ex = Assert.Throws<ArgumentException>(() =>
{
SqlColumnEncryptionAzureKeyVaultProvider azureKeyProvider = new SqlColumnEncryptionAzureKeyVaultProvider(
new SqlClientCustomTokenCredential(), trustedEndpoints);
});
Assert.Matches("One or more of the elements in trustedEndpoints are null or empty or consist of only whitespace.", ex.Message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ static DataTestUtility()
}

AKVOriginalUrl = c.AzureKeyVaultURL;
if (!string.IsNullOrEmpty(AKVOriginalUrl) && Uri.TryCreate(AKVOriginalUrl, UriKind.Absolute, out Uri AKVBaseUri))
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was creating a new local variable and not updating the static field in DataTestUtility. When the static AKVBaseUri was used later to instantiate a KeyClient, it was null.

if (!string.IsNullOrEmpty(AKVOriginalUrl) && Uri.TryCreate(AKVOriginalUrl, UriKind.Absolute, out AKVBaseUri))
{
AKVBaseUri = new Uri(AKVBaseUri, "/");
AKVBaseUrl = AKVBaseUri.AbsoluteUri;
Expand Down