diff --git a/build.proj b/build.proj
index edebcec39e..32f1734db9 100644
--- a/build.proj
+++ b/build.proj
@@ -25,7 +25,7 @@
-
+
@@ -34,7 +34,7 @@
-
+
@@ -116,14 +116,14 @@
-
+
-
+
diff --git a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj
index 9a32df9809..77b6e7e1be 100644
--- a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj
+++ b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj
@@ -6,7 +6,7 @@
{9073ABEF-92E0-4702-BB23-2C99CEF9BDD7}
netcoreapp
netfx
- Debug;Release;net46-Release;net46-Debug;netcoreapp2.1-Debug;netcoreapp2.1-Release;
+ Debug;Release;net46-Release;net46-Debug;netcoreapp2.1-Debug;netcoreapp2.1-Release;netcoreapp3.1-Debug;netcoreapp3.1-Release
AnyCPU;x86;x64
$(ObjFolder)$(Configuration).$(Platform)\$(AddOnName)
$(BinFolder)$(Configuration).$(Platform)\$(AddOnName)
diff --git a/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props b/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props
index 4fc891665f..e2303ef132 100644
--- a/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props
+++ b/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props
@@ -19,6 +19,7 @@
netcoreapp2.1
+ netcoreapp3.1
net46
diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj
index dad15bc623..0902edd7c1 100644
--- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj
@@ -1,7 +1,8 @@
false
- netcoreapp2.1;netcoreapp3.1;netstandard2.0
+ netcoreapp2.1;netcoreapp3.1;netstandard2.0;netstandard2.1
+ netstandard2.1
$(ObjFolder)$(Configuration)\$(AssemblyName)\ref\
$(BinFolder)$(Configuration)\$(AssemblyName)\ref\
$(OutputPath)\$(TargetFramework)\Microsoft.Data.SqlClient.xml
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
index 9232078830..8074efc2e8 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
@@ -1,7 +1,8 @@
Microsoft.Data.SqlClient
- netcoreapp2.1;netcoreapp3.1;netstandard2.0
+ netcoreapp2.1;netcoreapp3.1;netstandard2.0;netstandard2.1
+ netstandard2.1
Strings.PlatformNotSupported_DataSqlClient
$(OS)
true
@@ -226,11 +227,27 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -238,26 +255,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AlwaysEncryptedAttestationException.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AlwaysEncryptedAttestationException.cs
similarity index 100%
rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AlwaysEncryptedAttestationException.NetCoreApp.cs
rename to src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AlwaysEncryptedAttestationException.cs
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AlwaysEncryptedEnclaveProviderUtils.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AlwaysEncryptedEnclaveProviderUtils.NetCoreApp.cs
deleted file mode 100644
index 066d33be25..0000000000
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AlwaysEncryptedEnclaveProviderUtils.NetCoreApp.cs
+++ /dev/null
@@ -1,55 +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.Linq;
-
-namespace Microsoft.Data.SqlClient
-{
- internal class EnclavePublicKey
- {
- public byte[] PublicKey { get; set; }
-
- public EnclavePublicKey(byte[] payload)
- {
- PublicKey = payload;
- }
- }
-
- internal class EnclaveDiffieHellmanInfo
- {
- public int Size { get; private set; }
-
- public byte[] PublicKey { get; private set; }
-
- public byte[] PublicKeySignature { get; private set; }
-
- public EnclaveDiffieHellmanInfo(byte[] payload)
- {
- Size = payload.Length;
-
- int offset = 0;
- int publicKeySize = BitConverter.ToInt32(payload, offset);
- offset += sizeof(int);
-
- int publicKeySignatureSize = BitConverter.ToInt32(payload, offset);
- offset += sizeof(int);
-
- PublicKey = payload.Skip(offset).Take(publicKeySize).ToArray();
- offset += publicKeySize;
-
- PublicKeySignature = payload.Skip(offset).Take(publicKeySignatureSize).ToArray();
- offset += publicKeySignatureSize;
- }
- }
-
- internal enum EnclaveType
- {
- None = 0,
-
- Vbs = 1,
-
- Sgx = 2
- }
-}
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AlwaysEncryptedEnclaveProviderUtils.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AlwaysEncryptedEnclaveProviderUtils.cs
new file mode 100644
index 0000000000..23abf6b247
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AlwaysEncryptedEnclaveProviderUtils.cs
@@ -0,0 +1,153 @@
+// 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.Diagnostics;
+using System.Linq;
+using System.Security.Cryptography;
+
+namespace Microsoft.Data.SqlClient
+{
+ internal class EnclavePublicKey
+ {
+ public byte[] PublicKey { get; set; }
+
+ public EnclavePublicKey(byte[] payload)
+ {
+ PublicKey = payload;
+ }
+ }
+
+ internal class EnclaveDiffieHellmanInfo
+ {
+ public int Size { get; private set; }
+
+ public byte[] PublicKey { get; private set; }
+
+ public byte[] PublicKeySignature { get; private set; }
+
+ public EnclaveDiffieHellmanInfo(byte[] payload)
+ {
+ Size = payload.Length;
+
+ int offset = 0;
+ int publicKeySize = BitConverter.ToInt32(payload, offset);
+ offset += sizeof(int);
+
+ int publicKeySignatureSize = BitConverter.ToInt32(payload, offset);
+ offset += sizeof(int);
+
+ PublicKey = payload.Skip(offset).Take(publicKeySize).ToArray();
+ offset += publicKeySize;
+
+ PublicKeySignature = payload.Skip(offset).Take(publicKeySignatureSize).ToArray();
+ offset += publicKeySignatureSize;
+ }
+ }
+
+ internal enum EnclaveType
+ {
+ None = 0,
+
+ Vbs = 1,
+
+ Sgx = 2
+ }
+
+ // Contains methods to convert cryptography keys between different formats.
+ internal sealed class KeyConverter
+ {
+ // The RSA public key blob is structured as follows:
+ // BCRYPT_RSAKEY_BLOB header
+ // byte[ExponentSize] publicExponent
+ // byte[ModulusSize] modulus
+ private readonly struct RSAPublicKeyBlob
+ {
+ // Size of an RSA public key blob
+ internal static readonly int Size = 539;
+ // Size of the BCRYPT_RSAKEY_BLOB header
+ internal static readonly int HeaderSize = 27;
+ // Size of the exponent (final 3 bytes of the header)
+ internal static readonly int ExponentSize = 3;
+ // Size of the modulus (remaining bytes after the header)
+ internal static readonly int ModulusSize = Size - HeaderSize;
+ internal static readonly int ExponentOffset = HeaderSize - ExponentSize;
+ internal static readonly int ModulusOffset = HeaderSize;
+ }
+
+ // Extracts the public key's modulus and exponent from an RSA public key blob
+ // and returns an RSAParameters object
+ internal static RSAParameters RSAPublicKeyBlobToParams(byte[] keyBlob)
+ {
+ Debug.Assert(keyBlob.Length == RSAPublicKeyBlob.Size,
+ $"RSA public key blob was not the expected length. Actual: {keyBlob.Length}. Expected: {RSAPublicKeyBlob.Size}");
+ return new RSAParameters()
+ {
+ Exponent = keyBlob.Skip(RSAPublicKeyBlob.ExponentOffset).Take(RSAPublicKeyBlob.ExponentSize).ToArray(),
+ Modulus = keyBlob.Skip(RSAPublicKeyBlob.ModulusOffset).Take(RSAPublicKeyBlob.ModulusSize).ToArray()
+ };
+ }
+
+ // The ECC public key blob is structured as follows:
+ // BCRYPT_ECCKEY_BLOB header
+ // byte[KeySize] X
+ // byte[KeySize] Y
+ private readonly struct ECCPublicKeyBlob
+ {
+ // Size of an ECC public key blob
+ internal static readonly int Size = 104;
+ // Size of the BCRYPT_ECCKEY_BLOB header
+ internal static readonly int HeaderSize = 8;
+ // Size of each coordinate
+ internal static readonly int KeySize = (Size - HeaderSize) / 2;
+ }
+
+ // Magic numbers identifying blob types
+ // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wcce/cba27df5-4880-4f95-a879-783f8657e53b
+ private readonly struct KeyBlobMagicNumber
+ {
+ internal static readonly byte[] ECDHPublicP384 = new byte[] { 0x45, 0x43, 0x4b, 0x33 };
+ }
+
+ // Extracts the public key's X and Y coordinates from an ECC public key blob
+ // and returns an ECParameters object
+ internal static ECParameters ECCPublicKeyBlobToParams(byte[] keyBlob)
+ {
+ Debug.Assert(keyBlob.Length == ECCPublicKeyBlob.Size,
+ $"ECC public key blob was not the expected length. Actual: {keyBlob.Length}. Expected: {ECCPublicKeyBlob.Size}");
+ return new ECParameters
+ {
+ Curve = ECCurve.NamedCurves.nistP384,
+ Q = new ECPoint
+ {
+ X = keyBlob.Skip(ECCPublicKeyBlob.HeaderSize).Take(ECCPublicKeyBlob.KeySize).ToArray(),
+ Y = keyBlob.Skip(ECCPublicKeyBlob.HeaderSize + ECCPublicKeyBlob.KeySize).Take(ECCPublicKeyBlob.KeySize).ToArray()
+ },
+ };
+ }
+
+ // Serializes an ECDiffieHellmanPublicKey to an ECC public key blob
+ // "ECDiffieHellmanPublicKey.ToByteArray() doesn't have a (standards-)defined export
+ // format. The version used by ECDiffieHellmanPublicKeyCng is Windows-specific"
+ // from https://github.com/dotnet/runtime/issues/27276
+ // => ECDiffieHellmanPublicKey.ToByteArray() is not supported in Unix
+ internal static byte[] ECDHPublicKeyToECCKeyBlob(ECDiffieHellmanPublicKey publicKey)
+ {
+ byte[] keyBlob = new byte[ECCPublicKeyBlob.Size];
+
+ // Set magic number
+ Array.Copy(KeyBlobMagicNumber.ECDHPublicP384, 0, keyBlob, 0, 4);
+ // Set key size
+ keyBlob[4] = (byte)ECCPublicKeyBlob.KeySize;
+
+ ECPoint ecPoint = publicKey.ExportParameters().Q;
+ Debug.Assert(ecPoint.X.Length == ECCPublicKeyBlob.KeySize && ecPoint.Y.Length == ECCPublicKeyBlob.KeySize,
+ $"ECDH public key was not the expected length. Actual (X): {ecPoint.X.Length}. Actual (Y): {ecPoint.Y.Length} Expected: {ECCPublicKeyBlob.Size}");
+ // Copy x and y coordinates to key blob
+ Array.Copy(ecPoint.X, 0, keyBlob, ECCPublicKeyBlob.HeaderSize, ECCPublicKeyBlob.KeySize);
+ Array.Copy(ecPoint.Y, 0, keyBlob, ECCPublicKeyBlob.HeaderSize + ECCPublicKeyBlob.KeySize, ECCPublicKeyBlob.KeySize);
+ return keyBlob;
+ }
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AzureAttestationBasedEnclaveProvider.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AzureAttestationBasedEnclaveProvider.cs
similarity index 96%
rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AzureAttestationBasedEnclaveProvider.NetCoreApp.cs
rename to src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AzureAttestationBasedEnclaveProvider.cs
index a2a8270803..a4bff1a65d 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AzureAttestationBasedEnclaveProvider.NetCoreApp.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AzureAttestationBasedEnclaveProvider.cs
@@ -73,15 +73,15 @@ internal override void GetEnclaveSession(EnclaveSessionParameters enclaveSession
// Gets the information that SqlClient subsequently uses to initiate the process of attesting the enclave and to establish a secure session with the enclave.
internal override SqlEnclaveAttestationParameters GetAttestationParameters(string attestationUrl, byte[] customData, int customDataLength)
{
- ECDiffieHellmanCng clientDHKey = new ECDiffieHellmanCng(DiffieHellmanKeySize);
- clientDHKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
- clientDHKey.HashAlgorithm = CngAlgorithm.Sha256;
+ // The key derivation function and hash algorithm name are specified when key derivation is performed
+ ECDiffieHellman clientDHKey = ECDiffieHellman.Create();
+ clientDHKey.KeySize = DiffieHellmanKeySize;
byte[] attestationParam = PrepareAttestationParameters(attestationUrl, customData, customDataLength);
return new SqlEnclaveAttestationParameters(AzureBasedAttestationProtocolId, attestationParam, clientDHKey);
}
// When overridden in a derived class, performs enclave attestation, generates a symmetric key for the session, creates a an enclave session and stores the session information in the cache.
- internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellmanCng clientDHKey, EnclaveSessionParameters enclaveSessionParameters, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter)
+ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellman clientDHKey, EnclaveSessionParameters enclaveSessionParameters, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter)
{
sqlEnclaveSession = null;
counter = 0;
@@ -514,7 +514,7 @@ private void ValidateClaim(Dictionary claims, string claimName,
}
// Derives the shared secret between the client and enclave.
- private byte[] GetSharedSecret(EnclavePublicKey enclavePublicKey, byte[] nonce, EnclaveType enclaveType, EnclaveDiffieHellmanInfo enclaveDHInfo, ECDiffieHellmanCng clientDHKey)
+ private byte[] GetSharedSecret(EnclavePublicKey enclavePublicKey, byte[] nonce, EnclaveType enclaveType, EnclaveDiffieHellmanInfo enclaveDHInfo, ECDiffieHellman clientDHKey)
{
byte[] enclaveRsaPublicKey = enclavePublicKey.PublicKey;
@@ -529,17 +529,18 @@ private byte[] GetSharedSecret(EnclavePublicKey enclavePublicKey, byte[] nonce,
}
// Perform signature verification. The enclave's DiffieHellman public key was signed by the enclave's RSA public key.
- CngKey cngkey = CngKey.Import(enclaveRsaPublicKey, CngKeyBlobFormat.GenericPublicBlob);
- using (RSACng rsacng = new RSACng(cngkey))
+ RSAParameters rsaParams = KeyConverter.RSAPublicKeyBlobToParams(enclaveRsaPublicKey);
+ using (RSA rsa = RSA.Create(rsaParams))
{
- if (!rsacng.VerifyData(enclaveDHInfo.PublicKey, enclaveDHInfo.PublicKeySignature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1))
+ if (!rsa.VerifyData(enclaveDHInfo.PublicKey, enclaveDHInfo.PublicKeySignature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1))
{
throw new ArgumentException(Strings.GetSharedSecretFailed);
}
}
- CngKey key = CngKey.Import(enclaveDHInfo.PublicKey, CngKeyBlobFormat.GenericPublicBlob);
- return clientDHKey.DeriveKeyMaterial(key);
+ ECParameters ecParams = KeyConverter.ECCPublicKeyBlobToParams(enclaveDHInfo.PublicKey);
+ ECDiffieHellman enclaveDHKey = ECDiffieHellman.Create(ecParams);
+ return clientDHKey.DeriveKeyFromHash(enclaveDHKey.PublicKey, HashAlgorithmName.SHA256);
}
#endregion
}
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveDelegate.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveDelegate.NetCoreApp.cs
index db9f7a68f2..e1cff2d0e0 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveDelegate.NetCoreApp.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveDelegate.NetCoreApp.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
-using System.Security.Cryptography;
namespace Microsoft.Data.SqlClient
{
@@ -44,7 +43,7 @@ internal byte[] GetSerializedAttestationParameters(SqlEnclaveAttestationParamete
}
// clientDHPublicKey
- byte[] clientDHPublicKey = sqlEnclaveAttestationParameters.ClientDiffieHellmanKey.Key.Export(CngKeyBlobFormat.EccPublicBlob);
+ byte[] clientDHPublicKey = KeyConverter.ECDHPublicKeyToECCKeyBlob(sqlEnclaveAttestationParameters.ClientDiffieHellmanKey.PublicKey);
// clientDHPublicKey length
clientDHPublicKeyLengthBytes = GetUintBytes(enclaveType, clientDHPublicKey.Length, "clientDHPublicKeyLength");
@@ -54,7 +53,8 @@ internal byte[] GetSerializedAttestationParameters(SqlEnclaveAttestationParamete
throw SQL.NullArgumentInternal("clientDHPublicKeyLengthBytes", ClassName, GetSerializedAttestationParametersName);
}
- return CombineByteArrays(new[] { attestationProtocolBytes, attestationProtocolInputLengthBytes, attestationProtocolInputBytes, clientDHPublicKeyLengthBytes, clientDHPublicKey });
+ return CombineByteArrays(new[] { attestationProtocolBytes, attestationProtocolInputLengthBytes,
+ attestationProtocolInputBytes, clientDHPublicKeyLengthBytes, clientDHPublicKey });
}
///
@@ -88,7 +88,7 @@ internal void CreateEnclaveSession(SqlConnectionAttestationProtocol attestationP
sqlColumnEncryptionEnclaveProvider.CreateEnclaveSession(attestationInfo, attestationParameters.ClientDiffieHellmanKey, enclaveSessionParameters, customData, customDataLength, out sqlEnclaveSession, out counter);
- if (sqlEnclaveSession == null)
+ if (sqlEnclaveSession == null)
{
throw SQL.NullEnclaveSessionReturnedFromProvider(enclaveType, enclaveSessionParameters.AttestationUrl);
}
@@ -137,7 +137,7 @@ internal void InvalidateEnclaveSession(SqlConnectionAttestationProtocol attestat
sqlColumnEncryptionEnclaveProvider.InvalidateEnclaveSession(enclaveSessionParameters, enclaveSession);
}
-
+
internal SqlEnclaveAttestationParameters GetAttestationParameters(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string attestationUrl, byte[] customData, int customDataLength)
{
SqlColumnEncryptionEnclaveProvider sqlColumnEncryptionEnclaveProvider = GetEnclaveProvider(attestationProtocol, enclaveType);
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveProviderBase.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveProviderBase.cs
similarity index 100%
rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveProviderBase.NetCoreApp.cs
rename to src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveProviderBase.cs
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveSessionCache.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs
similarity index 100%
rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveSessionCache.NetCoreApp.cs
rename to src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.NetCoreApp.cs
index 064742be3c..bed6ada9e3 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.NetCoreApp.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.NetCoreApp.cs
@@ -30,15 +30,15 @@ internal override void GetEnclaveSession(EnclaveSessionParameters enclaveSession
// Gets the information that SqlClient subsequently uses to initiate the process of attesting the enclave and to establish a secure session with the enclave.
internal override SqlEnclaveAttestationParameters GetAttestationParameters(string attestationUrl, byte[] customData, int customDataLength)
{
- ECDiffieHellmanCng clientDHKey = new ECDiffieHellmanCng(384);
- clientDHKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
- clientDHKey.HashAlgorithm = CngAlgorithm.Sha256;
+ // The key derivation function and hash algorithm name are specified when key derivation is performed
+ ECDiffieHellman clientDHKey = ECDiffieHellman.Create();
+ clientDHKey.KeySize = 384;
return new SqlEnclaveAttestationParameters(2, new byte[] { }, clientDHKey);
}
// When overridden in a derived class, performs enclave attestation, generates a symmetric key for the session, creates a an enclave session and stores the session information in the cache.
- internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellmanCng clientDHKey, EnclaveSessionParameters enclaveSessionParameters, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter)
+ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellman clientDHKey, EnclaveSessionParameters enclaveSessionParameters, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter)
{
////for simulator: enclave does not send public key, and sends an empty attestation info
//// The only non-trivial content it sends is the session setup info (DH pubkey of enclave)
@@ -84,8 +84,9 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell
Buffer.BlockCopy(attestationInfo, attestationInfoOffset, trustedModuleDHPublicKeySignature, 0,
checked((int)sizeOfTrustedModuleDHPublicKeySignatureBuffer));
- CngKey k = CngKey.Import(trustedModuleDHPublicKey, CngKeyBlobFormat.EccPublicBlob);
- byte[] sharedSecret = clientDHKey.DeriveKeyMaterial(k);
+ ECParameters ecParams = KeyConverter.ECCPublicKeyBlobToParams(trustedModuleDHPublicKey);
+ ECDiffieHellman enclaveDHKey = ECDiffieHellman.Create(ecParams);
+ byte[] sharedSecret = clientDHKey.DeriveKeyFromHash(enclaveDHKey.PublicKey, HashAlgorithmName.SHA256);
long sessionId = BitConverter.ToInt64(enclaveSessionHandle, 0);
sqlEnclaveSession = AddEnclaveSessionToCache(enclaveSessionParameters, sharedSecret, sessionId, out counter);
}
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionCertificateStoreProvider.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionCertificateStoreProvider.Windows.cs
index e05025d2f8..c6f2786583 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionCertificateStoreProvider.Windows.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionCertificateStoreProvider.Windows.cs
@@ -482,10 +482,11 @@ private byte[] RSAEncrypt(byte[] plainText, X509Certificate2 certificate)
}
///
- /// Encrypt the text using specified certificate.
+ /// Decrypt the data using specified certificate.
///
/// Text to decrypt.
/// Certificate object.
+ /// Returns a decrypted blob or throws an exception if there are any errors.
private byte[] RSADecrypt(byte[] cipherText, X509Certificate2 certificate)
{
Debug.Assert((cipherText != null) && (cipherText.Length != 0));
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionEnclaveProvider.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionEnclaveProvider.NetCoreApp.cs
index c608036c6e..cca04fc323 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionEnclaveProvider.NetCoreApp.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionEnclaveProvider.NetCoreApp.cs
@@ -19,7 +19,7 @@ internal abstract partial class SqlColumnEncryptionEnclaveProvider
/// The length of the extra data needed for attestating the enclave.
/// The requested enclave session or null if the provider does not implement session caching.
/// A counter that the enclave provider is expected to increment each time SqlClient retrieves the session from the cache. The purpose of this field is to prevent replay attacks.
- internal abstract void CreateEnclaveSession(byte[] enclaveAttestationInfo, ECDiffieHellmanCng clientDiffieHellmanKey, EnclaveSessionParameters enclaveSessionParameters, byte[] customData, int customDataLength,
+ internal abstract void CreateEnclaveSession(byte[] enclaveAttestationInfo, ECDiffieHellman clientDiffieHellmanKey, EnclaveSessionParameters enclaveSessionParameters, byte[] customData, int customDataLength,
out SqlEnclaveSession sqlEnclaveSession, out long counter);
}
}
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlEnclaveAttestationParameters.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlEnclaveAttestationParameters.NetCoreApp.cs
index 1f59daf511..739187a7e9 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlEnclaveAttestationParameters.NetCoreApp.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlEnclaveAttestationParameters.NetCoreApp.cs
@@ -14,10 +14,10 @@ internal partial class SqlEnclaveAttestationParameters
private static readonly string _className = "EnclaveAttestationParameters";
///
- internal ECDiffieHellmanCng ClientDiffieHellmanKey { get; }
+ internal ECDiffieHellman ClientDiffieHellmanKey { get; }
///
- internal SqlEnclaveAttestationParameters(int protocol, byte[] input, ECDiffieHellmanCng clientDiffieHellmanKey)
+ internal SqlEnclaveAttestationParameters(int protocol, byte[] input, ECDiffieHellman clientDiffieHellmanKey)
{
_input = input ?? throw SQL.NullArgumentInConstructorInternal(_inputName, _className);
Protocol = protocol;
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProvider.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProvider.cs
similarity index 100%
rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProvider.NetCoreApp.cs
rename to src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProvider.cs
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs
similarity index 91%
rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.NetCoreApp.cs
rename to src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs
index 66f3f71a65..663b4a4e19 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.NetCoreApp.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs
@@ -94,14 +94,15 @@ internal override void GetEnclaveSession(EnclaveSessionParameters enclaveSession
// Gets the information that SqlClient subsequently uses to initiate the process of attesting the enclave and to establish a secure session with the enclave.
internal override SqlEnclaveAttestationParameters GetAttestationParameters(string attestationUrl, byte[] customData, int customDataLength)
{
- ECDiffieHellmanCng clientDHKey = new ECDiffieHellmanCng(DiffieHellmanKeySize);
- clientDHKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
- clientDHKey.HashAlgorithm = CngAlgorithm.Sha256;
+ // The key derivation function and hash algorithm name are specified when key derivation is performed
+ ECDiffieHellman clientDHKey = ECDiffieHellman.Create();
+ clientDHKey.KeySize = DiffieHellmanKeySize;
+
return new SqlEnclaveAttestationParameters(VsmHGSProtocolId, new byte[] { }, clientDHKey);
}
// When overridden in a derived class, performs enclave attestation, generates a symmetric key for the session, creates a an enclave session and stores the session information in the cache.
- internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellmanCng clientDHKey, EnclaveSessionParameters enclaveSessionParameters, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter)
+ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellman clientDHKey, EnclaveSessionParameters enclaveSessionParameters, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter)
{
sqlEnclaveSession = null;
counter = 0;
@@ -295,14 +296,12 @@ private void VerifyEnclaveReportSignature(EnclaveReportPackage enclaveReportPack
}
// IDK_S is contained in healthReport cert public key
- RSA rsacsp = healthReportCert.GetRSAPublicKey();
- RSAParameters rsaparams = rsacsp.ExportParameters(includePrivateParameters: false);
- RSACng rsacng = new RSACng();
- rsacng.ImportParameters(rsaparams);
-
- if (!rsacng.VerifyData(enclaveReportPackage.ReportAsBytes, enclaveReportPackage.SignatureBlob, HashAlgorithmName.SHA256, RSASignaturePadding.Pss))
+ using (RSA rsa = healthReportCert.GetRSAPublicKey())
{
- throw new ArgumentException(Strings.VerifyEnclaveReportFailed);
+ if (!rsa.VerifyData(enclaveReportPackage.ReportAsBytes, enclaveReportPackage.SignatureBlob, HashAlgorithmName.SHA256, RSASignaturePadding.Pss))
+ {
+ throw new ArgumentException(Strings.VerifyEnclaveReportFailed);
+ }
}
}
@@ -349,20 +348,22 @@ private void VerifyEnclavePolicyProperty(string property, uint actual, uint expe
}
// Derives the shared secret between the client and enclave.
- private byte[] GetSharedSecret(EnclavePublicKey enclavePublicKey, EnclaveDiffieHellmanInfo enclaveDHInfo, ECDiffieHellmanCng clientDHKey)
+ private byte[] GetSharedSecret(EnclavePublicKey enclavePublicKey, EnclaveDiffieHellmanInfo enclaveDHInfo, ECDiffieHellman clientDHKey)
{
// Perform signature verification. The enclave's DiffieHellman public key was signed by the enclave's RSA public key.
- CngKey cngkey = CngKey.Import(enclavePublicKey.PublicKey, CngKeyBlobFormat.GenericPublicBlob);
- RSACng rsacng = new RSACng(cngkey);
- if (!rsacng.VerifyData(enclaveDHInfo.PublicKey, enclaveDHInfo.PublicKeySignature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1))
+ RSAParameters rsaParams = KeyConverter.RSAPublicKeyBlobToParams(enclavePublicKey.PublicKey);
+ using (RSA rsa = RSA.Create(rsaParams))
{
- throw new ArgumentException(Strings.GetSharedSecretFailed);
+ if (!rsa.VerifyData(enclaveDHInfo.PublicKey, enclaveDHInfo.PublicKeySignature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1))
+ {
+ throw new ArgumentException(Strings.GetSharedSecretFailed);
+ }
}
- CngKey key = CngKey.Import(enclaveDHInfo.PublicKey, CngKeyBlobFormat.GenericPublicBlob);
- return clientDHKey.DeriveKeyMaterial(key);
+ ECParameters ecParams = KeyConverter.ECCPublicKeyBlobToParams(enclaveDHInfo.PublicKey);
+ ECDiffieHellman enclaveDHKey = ECDiffieHellman.Create(ecParams);
+ return clientDHKey.DeriveKeyFromHash(enclaveDHKey.PublicKey, HashAlgorithmName.SHA256);
}
-
#endregion
}
}
diff --git a/src/Microsoft.Data.SqlClient/tests/Directory.Build.props b/src/Microsoft.Data.SqlClient/tests/Directory.Build.props
index 5d26340cf8..3225e9461a 100644
--- a/src/Microsoft.Data.SqlClient/tests/Directory.Build.props
+++ b/src/Microsoft.Data.SqlClient/tests/Directory.Build.props
@@ -7,6 +7,7 @@
net46
+ netcoreapp3.1
netcoreapp2.1
Project
@@ -15,20 +16,20 @@
- $(TargetNetCoreVersion)
+ $(TargetNetCoreVersion)
- $(TargetNetCoreVersion)
- $(TargetNetFxVersion)
+ $(TargetNetCoreVersion)
+ $(TargetNetFxVersion)
- $(Configuration.Split('-')[0])
+ $(Configuration.Split('-')[0])
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj
index ed7e701212..cbaa4a9520 100644
--- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj
+++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj
@@ -10,20 +10,20 @@
$(BinFolder)$(Configuration).$(Platform).$(AssemblyName)
-
-
-
+
+
+
+
+
-
-
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs
index f0b08da092..e1eae7b608 100644
--- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs
@@ -52,8 +52,10 @@ public class SqlConnectionStringBuilderTest
[InlineData("PersistSecurityInfo = true")]
[InlineData("Pooling = no")]
[InlineData("Pooling = false")]
+#if netcoreapp // PoolBlockingPeriod is not supported in .NET Standard
[InlineData("PoolBlockingPeriod = Auto")]
[InlineData("PoolBlockingperiod = NeverBlock")]
+#endif
[InlineData("Replication = true")]
[InlineData("Transaction Binding = Explicit Unbind")]
[InlineData("Trust Server Certificate = true")]
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs
index bb74323fe0..5096d15af4 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs
@@ -18,18 +18,16 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted
{
///
/// Always Encrypted public API Manual tests.
- /// TODO: These tests are marked as Windows only for now but should be run for all platforms once the Master Key is accessible to this app from Azure Key Vault.
///
- [PlatformSpecific(TestPlatforms.Windows)]
- public class ApiShould : IClassFixture, IDisposable
+ public class ApiShould : IClassFixture, IDisposable
{
- private SQLSetupStrategyCertStoreProvider fixture;
+ private SQLSetupStrategy fixture;
private readonly string tableName;
- public ApiShould(SQLSetupStrategyCertStoreProvider fixture)
+ public ApiShould(PlatformSpecificTestContext context)
{
- this.fixture = fixture;
+ fixture = context.Fixture;
tableName = fixture.ApiTestTable.Name;
}
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAE.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAE.cs
index dccd65736a..dd2b2b2561 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAE.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAE.cs
@@ -11,18 +11,16 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted
{
///
/// Always Encrypted public API Manual tests.
- /// TODO: These tests are marked as Windows only for now but should be run for all platforms once the Master Key is accessible to this app from Azure Key Vault.
///
- [PlatformSpecific(TestPlatforms.Windows)]
- public class BulkCopyAE : IClassFixture, IDisposable
+ public class BulkCopyAE : IClassFixture, IDisposable
{
- private SQLSetupStrategyCertStoreProvider fixture;
+ private SQLSetupStrategy fixture;
private readonly string tableName;
- public BulkCopyAE(SQLSetupStrategyCertStoreProvider fixture)
+ public BulkCopyAE(PlatformSpecificTestContext context)
{
- this.fixture = fixture;
+ fixture = context.Fixture;
tableName = fixture.BulkCopyAETestTable.Name;
}
@@ -34,7 +32,7 @@ public void TestBulkCopyString(string connectionString)
dataTable.Columns.Add("c1", typeof(string));
var dataRow = dataTable.NewRow();
- String result = "stringValue";
+ string result = "stringValue";
dataRow["c1"] = result;
dataTable.Rows.Add(dataRow);
dataTable.AcceptChanges();
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs
index 111c64fd43..cf2da1c4b6 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs
@@ -10,20 +10,18 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted
{
///
/// Always Encrypted public API Manual tests.
- /// TODO: These tests are marked as Windows only for now but should be run for all platforms once the Master Key is accessible to this app from Azure Key Vault.
///
- [PlatformSpecific(TestPlatforms.Windows)]
- public class BulkCopyAEErrorMessage : IClassFixture
+ public class BulkCopyAEErrorMessage : IClassFixture
{
- private SQLSetupStrategyCertStoreProvider _fixture;
-
+ private SQLSetupStrategy _fixture;
+
private readonly string _tableName;
private readonly string _columnName;
- public BulkCopyAEErrorMessage(SQLSetupStrategyCertStoreProvider fixture)
+ public BulkCopyAEErrorMessage(PlatformSpecificTestContext context)
{
- _fixture = fixture;
- _tableName = fixture.BulkCopyAEErrorMessageTestTable.Name;
+ _fixture = context.Fixture;
+ _tableName = _fixture.BulkCopyAEErrorMessageTestTable.Name;
_columnName = "c1";
}
@@ -35,8 +33,8 @@ public void TextToIntErrorMessageTest(string connectionString)
DataTable dataTable = CreateDataTable(value);
Assert.True(StringToIntTest(connectionString, _tableName, dataTable, value, dataTable.Rows.Count), "Did not get any exceptions for DataTable when converting data from 'string' to 'int' datatype!");
- Assert.True(StringToIntTest(connectionString, _tableName, dataTable.Select(), value, dataTable.Rows.Count),"Did not get any exceptions for DataRow[] when converting data from 'string' to 'int' datatype!");
- Assert.True(StringToIntTest(connectionString, _tableName, dataTable.CreateDataReader(), value, -1),"Did not get any exceptions for DataReader when converting data from 'string' to 'int' datatype!");
+ Assert.True(StringToIntTest(connectionString, _tableName, dataTable.Select(), value, dataTable.Rows.Count), "Did not get any exceptions for DataRow[] when converting data from 'string' to 'int' datatype!");
+ Assert.True(StringToIntTest(connectionString, _tableName, dataTable.CreateDataReader(), value, -1), "Did not get any exceptions for DataReader when converting data from 'string' to 'int' datatype!");
}
private DataTable CreateDataTable(string value)
@@ -44,7 +42,7 @@ private DataTable CreateDataTable(string value)
var dataTable = new DataTable();
dataTable.Columns.Add(_columnName, typeof(string));
- var dataRow = dataTable.NewRow();
+ var dataRow = dataTable.NewRow();
dataRow[_columnName] = value;
dataTable.Rows.Add(dataRow);
dataTable.AcceptChanges();
@@ -90,7 +88,7 @@ private bool StringToIntTest(string connectionString, string targetTable, object
catch (Exception ex)
{
string pattern;
- object[] args =
+ object[] args =
new object[] { string.Empty, value.GetType().Name, targetType, 0, _columnName, rowNo };
if (rowNo == -1)
{
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/EnclaveAzureDatabaseTests.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/EnclaveAzureDatabaseTests.cs
index d90529976d..289ad6bc63 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/EnclaveAzureDatabaseTests.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/EnclaveAzureDatabaseTests.cs
@@ -68,7 +68,6 @@ public EnclaveAzureDatabaseTests()
}
}
- [PlatformSpecific(TestPlatforms.Windows)]
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsEnclaveAzureDatabaseSetup))]
public void ConnectToAzureDatabaseWithEnclave()
{
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/End2EndSmokeTests.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/End2EndSmokeTests.cs
index a8cbde4f1b..88fc0f6f66 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/End2EndSmokeTests.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/End2EndSmokeTests.cs
@@ -11,16 +11,15 @@
namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted
{
- [PlatformSpecific(TestPlatforms.Windows)]
- public class End2EndSmokeTests : IClassFixture, IDisposable
+ public class End2EndSmokeTests : IClassFixture, IDisposable
{
- private SQLSetupStrategyCertStoreProvider fixture;
+ private SQLSetupStrategy fixture;
private readonly string tableName;
- public End2EndSmokeTests(SQLSetupStrategyCertStoreProvider fixture)
+ public End2EndSmokeTests(PlatformSpecificTestContext context)
{
- this.fixture = fixture;
+ fixture = context.Fixture;
tableName = fixture.End2EndSmokeTable.Name;
}
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ExceptionTestAKVStore.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ExceptionTestAKVStore.cs
index 50eccd0b9e..a9503d69de 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ExceptionTestAKVStore.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ExceptionTestAKVStore.cs
@@ -163,7 +163,7 @@ public void InvalidCertificatePath()
Assert.Matches(errorMessage, ex2.Message);
}
- // [InlineData(true)] -> Enable with AE v2
+ [InlineData(true)]
[InlineData(false)]
[ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.IsAKVSetupAvailable))]
public void AkvStoreProviderVerifyFunctionWithInvalidSignature(bool fEnclaveEnabled)
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/SqlBulkCopyTruncation.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/SqlBulkCopyTruncation.cs
index cd2c2dadc9..32dd86cd94 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/SqlBulkCopyTruncation.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/SqlBulkCopyTruncation.cs
@@ -11,17 +11,16 @@
namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted
{
- [PlatformSpecific(TestPlatforms.Windows)]
- public class SqlBulkCopyTruncation : IClassFixture
+ public class SqlBulkCopyTruncation : IClassFixture
{
- private SQLSetupStrategyCertStoreProvider _fixture;
+ private SQLSetupStrategy _fixture;
private readonly Dictionary tableNames = new Dictionary();
- public SqlBulkCopyTruncation(SQLSetupStrategyCertStoreProvider fixture)
+ public SqlBulkCopyTruncation(PlatformSpecificTestContext context)
{
- _fixture = fixture;
- tableNames = fixture.sqlBulkTruncationTableNames;
+ _fixture = context.Fixture;
+ tableNames = _fixture.sqlBulkTruncationTableNames;
}
[ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringSetupForAE))]
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/SqlNullValues.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/SqlNullValues.cs
index 91d29836d0..caa174b3ce 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/SqlNullValues.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/SqlNullValues.cs
@@ -11,17 +11,16 @@
namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted
{
- [PlatformSpecific(TestPlatforms.Windows)]
- public class SqlNullValuesTests : IClassFixture, IDisposable
+ public class SqlNullValuesTests : IClassFixture, IDisposable
{
- private SQLSetupStrategyCertStoreProvider fixture;
+ private SQLSetupStrategy fixture;
private readonly string tableName;
private string UdfName = DatabaseHelper.GenerateUniqueName("SqlNullValuesRetVal");
private string UdfNameNotNull = DatabaseHelper.GenerateUniqueName("SqlNullValuesRetValNotNull");
- public SqlNullValuesTests(SQLSetupStrategyCertStoreProvider fixture)
+ public SqlNullValuesTests(PlatformSpecificTestContext context)
{
- this.fixture = fixture;
+ fixture = context.Fixture;
tableName = fixture.SqlNullValuesTable.Name;
// Disable the cache to avoid false failures.
SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled = false;
@@ -33,7 +32,7 @@ public SqlNullValuesTests(SQLSetupStrategyCertStoreProvider fixture)
{
sqlConnection.Open();
- using (SqlCommand cmd = new SqlCommand(String.Format("INSERT INTO [{0}] (c1) VALUES (@c1)", tableName), sqlConnection, null, SqlCommandColumnEncryptionSetting.Enabled))
+ using (SqlCommand cmd = new SqlCommand(string.Format("INSERT INTO [{0}] (c1) VALUES (@c1)", tableName), sqlConnection, null, SqlCommandColumnEncryptionSetting.Enabled))
{
SqlParameter param = cmd.Parameters.Add("@c1", SqlDbType.Int);
param.Value = DBNull.Value;
@@ -79,7 +78,7 @@ public void NullValueTests(string connString, ConnStringColumnEncryptionSetting
SqlParameter param;
// Create a command similarly
- using (SqlCommand cmd = new SqlCommand(String.Format("SELECT c1 FROM [{0}] ORDER BY c2 ASC", tableName),
+ using (SqlCommand cmd = new SqlCommand(string.Format("SELECT c1 FROM [{0}] ORDER BY c2 ASC", tableName),
sqlConn, null, commandSetting))
{
using (SqlDataReader reader = cmd.ExecuteReader())
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs
index dc165a2747..7183655c41 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
+using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup;
using Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.TestFixtures.Setup;
@@ -253,4 +254,30 @@ public void Dispose()
}
}
}
+
+ // Use this class as the fixture for AE tests to ensure only one platform-specific fixture
+ // is created for each test class
+ public class PlatformSpecificTestContext : IDisposable
+ {
+ private SQLSetupStrategy certStoreFixture = null;
+ private SQLSetupStrategy akvFixture = null;
+ public SQLSetupStrategy Fixture => certStoreFixture ?? akvFixture;
+
+ public PlatformSpecificTestContext()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ certStoreFixture = new SQLSetupStrategyCertStoreProvider();
+ }
+ else
+ {
+ akvFixture = new SQLSetupStrategyAzureKeyVault();
+ }
+ }
+
+ public void Dispose()
+ {
+ Fixture.Dispose();
+ }
+ }
}
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/AkvColumnMasterKey.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/AkvColumnMasterKey.cs
index a9469d79b6..353f7ac97a 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/AkvColumnMasterKey.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/AkvColumnMasterKey.cs
@@ -17,7 +17,7 @@ public AkvColumnMasterKey(string name, string akvUrl, SqlColumnEncryptionKeyStor
// For keys which allow enclave computation
byte[] cmkSign = akvProvider.SignColumnMasterKeyMetadata(akvUrl, allowEnclaveComputations);
- cmkSignStr = string.Concat("0x", BitConverter.ToString(cmkSign).Replace("-", string.Empty));
+ CmkSignStr = string.Concat("0x", BitConverter.ToString(cmkSign).Replace("-", string.Empty));
}
}
}
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/ColumnMasterKey.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/ColumnMasterKey.cs
index 5eb02ffcd9..4e4cf8acf8 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/ColumnMasterKey.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/ColumnMasterKey.cs
@@ -2,36 +2,29 @@
// 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.Data;
-using System.Data.SqlTypes;
-using Xunit;
-
namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup
{
public abstract class ColumnMasterKey : DbObject
{
-
protected ColumnMasterKey(string name) : base(name)
{
}
protected string KeyStoreProviderName { get; set; }
- protected string cmkSignStr { get; set; }
+ protected string CmkSignStr { get; set; }
public abstract string KeyPath { get; }
public override void Create(SqlConnection sqlConnection)
{
string sql;
- var connStrings = sqlConnection.ConnectionString;
- if (DataTestUtility.EnclaveEnabled && !String.IsNullOrEmpty(cmkSignStr))
+ if (DataTestUtility.EnclaveEnabled && !string.IsNullOrEmpty(CmkSignStr))
{
sql =
$@"CREATE COLUMN MASTER KEY [{Name}]
WITH (
KEY_STORE_PROVIDER_NAME = N'{KeyStoreProviderName}',
KEY_PATH = N'{KeyPath}',
- ENCLAVE_COMPUTATIONS (SIGNATURE = {cmkSignStr})
+ ENCLAVE_COMPUTATIONS (SIGNATURE = {CmkSignStr})
);";
}
else
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CspColumnMasterKey.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CspColumnMasterKey.cs
index 9e26b1105e..8a27b2b860 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CspColumnMasterKey.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CspColumnMasterKey.cs
@@ -21,7 +21,7 @@ public CspColumnMasterKey(string name, string certificateThumbprint, SqlColumnEn
KeyPath = string.Concat(CertificateStoreLocation.ToString(), "/", CertificateStoreName.ToString(), "/", Thumbprint);
byte[] cmkSign = certStoreProvider.SignColumnMasterKeyMetadata(KeyPath, allowEnclaveComputations);
- cmkSignStr = string.Concat("0x", BitConverter.ToString(cmkSign).Replace("-", string.Empty));
+ CmkSignStr = string.Concat("0x", BitConverter.ToString(cmkSign).Replace("-", string.Empty));
}
public CspColumnMasterKey(string name, string providerName, string cspKeyPath, SqlColumnEncryptionKeyStoreProvider certStoreProvider, bool allowEnclaveComputations) : base(name)
@@ -29,7 +29,7 @@ public CspColumnMasterKey(string name, string providerName, string cspKeyPath, S
KeyStoreProviderName = providerName;
KeyPath = cspKeyPath;
byte[] cmkSign = certStoreProvider.SignColumnMasterKeyMetadata(KeyPath, allowEnclaveComputations);
- cmkSignStr = string.Concat("0x", BitConverter.ToString(cmkSign).Replace("-", string.Empty));
+ CmkSignStr = string.Concat("0x", BitConverter.ToString(cmkSign).Replace("-", string.Empty));
}
}
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
index afbd056adb..810775db77 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
@@ -17,47 +17,47 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Common\System\Collections\DictionaryExtensions.cs
@@ -278,7 +278,7 @@
-
+
diff --git a/src/Microsoft.Data.SqlClient/tests/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj b/src/Microsoft.Data.SqlClient/tests/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj
index 5c1d2ce4c5..d526f2497c 100644
--- a/src/Microsoft.Data.SqlClient/tests/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj
+++ b/src/Microsoft.Data.SqlClient/tests/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj
@@ -1,7 +1,8 @@
- netstandard2.0
+ netstandard2.0;netstandard2.1
+ netstandard2.1
AnyCPU;x86;x64
$(ObjFolder)$(Configuration).$(Platform)\$(AssemblyName)
$(BinFolder)$(Configuration).$(Platform)\$(AssemblyName)
diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec
index 3e09d83333..362ffdd7c8 100644
--- a/tools/specs/Microsoft.Data.SqlClient.nuspec
+++ b/tools/specs/Microsoft.Data.SqlClient.nuspec
@@ -67,6 +67,17 @@ When using NuGet 3.x this package requires at least version 3.4.
+
+
+
+
+
+
+
+
+
+
+
@@ -93,6 +104,11 @@ When using NuGet 3.x this package requires at least version 3.4.
+
+
+
+
+
@@ -117,6 +133,10 @@ When using NuGet 3.x this package requires at least version 3.4.
+
+
+
+
@@ -148,6 +168,10 @@ When using NuGet 3.x this package requires at least version 3.4.
+
+
+
+
@@ -169,5 +193,10 @@ When using NuGet 3.x this package requires at least version 3.4.
+
+
+
+
+