From 05f2d1db76adba2bad159408fa7852a81c09d040 Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Thu, 18 Jun 2020 18:45:51 -0700 Subject: [PATCH 01/12] Add database name to enclave session cache key --- ...estationBasedEnclaveProvider.NetCoreApp.cs | 14 +++++------ .../SqlClient/EnclaveDelegate.NetCoreApp.cs | 25 ++++++++++--------- .../SqlClient/EnclaveDelegate.NetStandard.cs | 9 ++++--- .../EnclaveProviderBase.NetCoreApp.cs | 20 +++++++-------- .../EnclaveSessionCache.NetCoreApp.cs | 18 ++++++------- .../SimulatorEnclaveProvider.NetCoreApp.cs | 15 +++++------ ...umnEncryptionEnclaveProvider.NetCoreApp.cs | 3 ++- .../SqlColumnEncryptionEnclaveProvider.cs | 4 +-- .../Microsoft/Data/SqlClient/SqlCommand.cs | 14 ++++++----- ...ecureModeEnclaveProviderBase.NetCoreApp.cs | 14 +++++------ .../AzureAttestationBasedEnclaveProvider.cs | 14 +++++------ .../Data/SqlClient/EnclaveDelegate.cs | 24 ++++++++++-------- .../Data/SqlClient/EnclaveProviderBase.cs | 18 ++++++------- .../Data/SqlClient/EnclaveSessionCache.cs | 18 ++++++------- .../SqlClient/SimulatorEnclaveProvider.cs | 15 +++++------ .../SqlColumnEncryptionEnclaveProvider.cs | 6 ++--- .../Microsoft/Data/SqlClient/SqlCommand.cs | 15 ++++++----- .../VirtualSecureModeEnclaveProviderBase.cs | 14 +++++------ 18 files changed, 136 insertions(+), 124 deletions(-) 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.NetCoreApp.cs index 4a461b0532..06d9a4e5cf 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.NetCoreApp.cs @@ -65,9 +65,9 @@ internal class AzureAttestationEnclaveProvider : EnclaveProviderBase #region Internal methods // When overridden in a derived class, looks up an existing enclave session information in the enclave session cache. // If the enclave provider doesn't implement enclave session caching, this method is expected to return null in the sqlEnclaveSession parameter. - internal override void GetEnclaveSession(string servername, string attestationUrl, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) + internal override void GetEnclaveSession(string servername, string attestationUrl, string database, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) { - GetEnclaveSessionHelper(servername, attestationUrl, generateCustomData, out sqlEnclaveSession, out counter, out customData, out customDataLength); + GetEnclaveSessionHelper(servername, attestationUrl, database, generateCustomData, out sqlEnclaveSession, out counter, out customData, out customDataLength); } // Gets the information that SqlClient subsequently uses to initiate the process of attesting the enclave and to establish a secure session with the enclave. @@ -81,14 +81,14 @@ internal override SqlEnclaveAttestationParameters GetAttestationParameters(strin } // 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, string attestationUrl, string servername, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter) + internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellmanCng clientDHKey, string attestationUrl, string servername, string database, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter) { sqlEnclaveSession = null; counter = 0; try { ThreadRetryCache.Remove(Thread.CurrentThread.ManagedThreadId.ToString()); - sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, out counter); + sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, database, out counter); if (sqlEnclaveSession == null) { if (!string.IsNullOrEmpty(attestationUrl) && customData != null && customDataLength > 0) @@ -107,7 +107,7 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell byte[] sharedSecret = GetSharedSecret(attestInfo.Identity, nonce, attestInfo.EnclaveType, attestInfo.EnclaveDHInfo, clientDHKey); // add session to cache - sqlEnclaveSession = AddEnclaveSessionToCache(attestationUrl, servername, sharedSecret, attestInfo.SessionId, out counter); + sqlEnclaveSession = AddEnclaveSessionToCache(attestationUrl, servername, database, sharedSecret, attestInfo.SessionId, out counter); } else { @@ -126,9 +126,9 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell } // When overridden in a derived class, looks up and evicts an enclave session from the enclave session cache, if the provider implements session caching. - internal override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSessionToInvalidate) + internal override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, string database, SqlEnclaveSession enclaveSessionToInvalidate) { - InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, enclaveSessionToInvalidate); + InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, database, enclaveSessionToInvalidate); } #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 4ab9421bd9..440c2a309b 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 @@ -64,11 +64,12 @@ internal byte[] GetSerializedAttestationParameters(SqlEnclaveAttestationParamete /// enclave type /// servername /// attestation url for attestation service endpoint + /// The database that SqlClient contacts to. /// attestation info from SQL Server /// attestation parameters /// A set of extra data needed for attestating the enclave. /// The length of the extra data needed for attestating the enclave. - internal void CreateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string attestationUrl, + internal void CreateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string attestationUrl, string database, byte[] attestationInfo, SqlEnclaveAttestationParameters attestationParameters, byte[] customData, int customDataLength) { @@ -79,15 +80,14 @@ internal void CreateEnclaveSession(SqlConnectionAttestationProtocol attestationP SqlEnclaveSession sqlEnclaveSession = null; byte[] dummyCustomData = null; int dummyCustomDataLength; - - sqlColumnEncryptionEnclaveProvider.GetEnclaveSession(serverName, attestationUrl, false, out sqlEnclaveSession, out counter, out dummyCustomData, out dummyCustomDataLength); + sqlColumnEncryptionEnclaveProvider.GetEnclaveSession(serverName, attestationUrl, database, false, out sqlEnclaveSession, out counter, out dummyCustomData, out dummyCustomDataLength); if (sqlEnclaveSession != null) { return; } - sqlColumnEncryptionEnclaveProvider.CreateEnclaveSession(attestationInfo, attestationParameters.ClientDiffieHellmanKey, attestationUrl, serverName, customData, customDataLength, out sqlEnclaveSession, out counter); + sqlColumnEncryptionEnclaveProvider.CreateEnclaveSession(attestationInfo, attestationParameters.ClientDiffieHellmanKey, attestationUrl, serverName, database, customData, customDataLength, out sqlEnclaveSession, out counter); if (sqlEnclaveSession == null) { @@ -105,8 +105,9 @@ internal void CreateEnclaveSession(SqlConnectionAttestationProtocol attestationP /// enclave type /// server name /// url for attestation endpoint + /// The database that SqlClient contacts to. /// - internal EnclavePackage GenerateEnclavePackage(SqlConnectionAttestationProtocol attestationProtocol, Dictionary keysToBeSentToEnclave, string queryText, string enclaveType, string serverName, string enclaveAttestationUrl) + internal EnclavePackage GenerateEnclavePackage(SqlConnectionAttestationProtocol attestationProtocol, Dictionary keysToBeSentToEnclave, string queryText, string enclaveType, string serverName, string enclaveAttestationUrl, string database) { SqlEnclaveSession sqlEnclaveSession = null; @@ -116,7 +117,7 @@ internal EnclavePackage GenerateEnclavePackage(SqlConnectionAttestationProtocol try { - GetEnclaveSession(attestationProtocol, enclaveType, serverName, enclaveAttestationUrl, false, out sqlEnclaveSession, out counter, out dummyCustomData, out dummyCustomDataLength, throwIfNull: true); + GetEnclaveSession(attestationProtocol, enclaveType, serverName, enclaveAttestationUrl, database, false, out sqlEnclaveSession, out counter, out dummyCustomData, out dummyCustomDataLength, throwIfNull: true); } catch (Exception e) { @@ -133,10 +134,10 @@ internal EnclavePackage GenerateEnclavePackage(SqlConnectionAttestationProtocol return new EnclavePackage(byteArrayToBeSentToEnclave, sqlEnclaveSession); } - internal void InvalidateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string EnclaveAttestationUrl, SqlEnclaveSession enclaveSession) + internal void InvalidateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string EnclaveAttestationUrl, string database, SqlEnclaveSession enclaveSession) { SqlColumnEncryptionEnclaveProvider sqlColumnEncryptionEnclaveProvider = GetEnclaveProvider(attestationProtocol, enclaveType); - sqlColumnEncryptionEnclaveProvider.InvalidateEnclaveSession(serverName, EnclaveAttestationUrl, enclaveSession); + sqlColumnEncryptionEnclaveProvider.InvalidateEnclaveSession(serverName, EnclaveAttestationUrl, database, enclaveSession); } @@ -207,16 +208,16 @@ private string ConvertAttestationProtocolToString(SqlConnectionAttestationProtoc } } - internal void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string enclaveAttestationUrl, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out byte[] customData, out int customDataLength) + internal void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string enclaveAttestationUrl, string database, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out byte[] customData, out int customDataLength) { long counter; - GetEnclaveSession(attestationProtocol, enclaveType, serverName, enclaveAttestationUrl, generateCustomData, out sqlEnclaveSession, out counter, out customData, out customDataLength, throwIfNull: false); + GetEnclaveSession(attestationProtocol, enclaveType, serverName, enclaveAttestationUrl, database, generateCustomData, out sqlEnclaveSession, out counter, out customData, out customDataLength, throwIfNull: false); } - private void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string enclaveAttestationUrl, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength, bool throwIfNull) + private void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string enclaveAttestationUrl, string database, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength, bool throwIfNull) { SqlColumnEncryptionEnclaveProvider sqlColumnEncryptionEnclaveProvider = GetEnclaveProvider(attestationProtocol, enclaveType); - sqlColumnEncryptionEnclaveProvider.GetEnclaveSession(serverName, enclaveAttestationUrl, generateCustomData, out sqlEnclaveSession, out counter, out customData, out customDataLength); + sqlColumnEncryptionEnclaveProvider.GetEnclaveSession(serverName, enclaveAttestationUrl, database, generateCustomData, out sqlEnclaveSession, out counter, out customData, out customDataLength); if (throwIfNull && sqlEnclaveSession == null) { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveDelegate.NetStandard.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveDelegate.NetStandard.cs index 63db20022a..b6083296f9 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveDelegate.NetStandard.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveDelegate.NetStandard.cs @@ -25,27 +25,28 @@ internal byte[] GetSerializedAttestationParameters( /// enclave type /// servername /// attestation url for attestation service endpoint + /// The database that SqlClient contacts to. /// attestation info from SQL Server /// attestation parameters /// A set of extra data needed for attestating the enclave. /// The length of the extra data needed for attestating the enclave. - internal void CreateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string attestationUrl, + internal void CreateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string attestationUrl, string database, byte[] attestationInfo, SqlEnclaveAttestationParameters attestationParameters, byte[] customData, int customDataLength) { throw new PlatformNotSupportedException(); } - internal void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string enclaveAttestationUrl, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out byte[] customData, out int customDataLength) + internal void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string enclaveAttestationUrl, string database, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out byte[] customData, out int customDataLength) { throw new PlatformNotSupportedException(); } - internal EnclavePackage GenerateEnclavePackage(SqlConnectionAttestationProtocol attestationProtocol, Dictionary keysTobeSentToEnclave, string queryText, string enclaveType, string serverName, string enclaveAttestationUrl) + internal EnclavePackage GenerateEnclavePackage(SqlConnectionAttestationProtocol attestationProtocol, Dictionary keysTobeSentToEnclave, string queryText, string enclaveType, string serverName, string enclaveAttestationUrl, string database) { throw new PlatformNotSupportedException(); } - internal void InvalidateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string EnclaveAttestationUrl, SqlEnclaveSession enclaveSession) + internal void InvalidateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string EnclaveAttestationUrl, string database, SqlEnclaveSession enclaveSession) { throw new PlatformNotSupportedException(); } 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.NetCoreApp.cs index 213b6b162b..089a52512f 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveProviderBase.NetCoreApp.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveProviderBase.NetCoreApp.cs @@ -87,13 +87,13 @@ internal abstract class EnclaveProviderBase : SqlColumnEncryptionEnclaveProvider protected static readonly MemoryCache ThreadRetryCache = new MemoryCache("ThreadRetryCache"); #endregion - #region Public methods + #region Protected methods // Helper method to get the enclave session from the cache if present - protected void GetEnclaveSessionHelper(string servername, string attestationUrl, bool shouldGenerateNonce, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) + protected void GetEnclaveSessionHelper(string servername, string attestationUrl, string database, bool shouldGenerateNonce, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) { customData = null; customDataLength = 0; - sqlEnclaveSession = SessionCache.GetEnclaveSession(servername, attestationUrl, out counter); + sqlEnclaveSession = SessionCache.GetEnclaveSession(servername, attestationUrl, database, out counter); if (sqlEnclaveSession == null) { @@ -128,7 +128,7 @@ protected void GetEnclaveSessionHelper(string servername, string attestationUrl, { // While the current thread is waiting for event to be signaled and in the meanwhile we already completed the attestation on different thread // then we need to signal the event here - sqlEnclaveSession = SessionCache.GetEnclaveSession(servername, attestationUrl, out counter); + sqlEnclaveSession = SessionCache.GetEnclaveSession(servername, attestationUrl, database, out counter); if (sqlEnclaveSession != null && !sameThreadRetry) { lock (lockUpdateSessionLock) @@ -194,21 +194,21 @@ protected void UpdateEnclaveSessionLockStatus(SqlEnclaveSession sqlEnclaveSessio } // Helper method to remove the enclave session from the cache - protected void InvalidateEnclaveSessionHelper(string servername, string attestationUrl, SqlEnclaveSession enclaveSessionToInvalidate) + protected void InvalidateEnclaveSessionHelper(string servername, string attestationUrl, string database, SqlEnclaveSession enclaveSessionToInvalidate) { - SessionCache.InvalidateSession(servername, attestationUrl, enclaveSessionToInvalidate); + SessionCache.InvalidateSession(servername, attestationUrl, database, enclaveSessionToInvalidate); } // Helper method for getting the enclave session from the session cache - protected SqlEnclaveSession GetEnclaveSessionFromCache(string attestationUrl, string servername, out long counter) + protected SqlEnclaveSession GetEnclaveSessionFromCache(string attestationUrl, string servername, string database, out long counter) { - return SessionCache.GetEnclaveSession(servername, attestationUrl, out counter); + return SessionCache.GetEnclaveSession(servername, attestationUrl, database, out counter); } // Helper method for adding the enclave session to the session cache - protected SqlEnclaveSession AddEnclaveSessionToCache(string attestationUrl, string servername, byte[] sharedSecret, long sessionId, out long counter) + protected SqlEnclaveSession AddEnclaveSessionToCache(string attestationUrl, string servername, string database, byte[] sharedSecret, long sessionId, out long counter) { - return SessionCache.CreateSession(attestationUrl, servername, sharedSecret, sessionId, out counter); + return SessionCache.CreateSession(attestationUrl, servername, database, sharedSecret, sessionId, out counter); } } #endregion 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.NetCoreApp.cs index 1445918d37..ffcea85e07 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveSessionCache.NetCoreApp.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveSessionCache.NetCoreApp.cs @@ -22,23 +22,23 @@ internal class EnclaveSessionCache private static int enclaveCacheTimeOutInHours = 8; // Retrieves a SqlEnclaveSession from the cache - internal SqlEnclaveSession GetEnclaveSession(string servername, string attestationUrl, out long counter) + internal SqlEnclaveSession GetEnclaveSession(string servername, string attestationUrl, string database, out long counter) { - string cacheKey = GenerateCacheKey(servername, attestationUrl); + string cacheKey = GenerateCacheKey(servername, attestationUrl, database); SqlEnclaveSession enclaveSession = enclaveMemoryCache[cacheKey] as SqlEnclaveSession; counter = Interlocked.Increment(ref _counter); return enclaveSession; } // Invalidates a SqlEnclaveSession entry in the cache - internal void InvalidateSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSessionToInvalidate) + internal void InvalidateSession(string serverName, string enclaveAttestationUrl, string database, SqlEnclaveSession enclaveSessionToInvalidate) { - string cacheKey = GenerateCacheKey(serverName, enclaveAttestationUrl); + string cacheKey = GenerateCacheKey(serverName, enclaveAttestationUrl, database); lock (enclaveCacheLock) { long counter; - SqlEnclaveSession enclaveSession = GetEnclaveSession(serverName, enclaveAttestationUrl, out counter); + SqlEnclaveSession enclaveSession = GetEnclaveSession(serverName, enclaveAttestationUrl, database, out counter); if (enclaveSession != null && enclaveSession.SessionId == enclaveSessionToInvalidate.SessionId) { @@ -52,9 +52,9 @@ internal void InvalidateSession(string serverName, string enclaveAttestationUrl, } // Creates a new SqlEnclaveSession and adds it to the cache - internal SqlEnclaveSession CreateSession(string attestationUrl, string serverName, byte[] sharedSecret, long sessionId, out long counter) + internal SqlEnclaveSession CreateSession(string attestationUrl, string serverName, string database, byte[] sharedSecret, long sessionId, out long counter) { - string cacheKey = GenerateCacheKey(serverName, attestationUrl); + string cacheKey = GenerateCacheKey(serverName, attestationUrl, database); SqlEnclaveSession enclaveSession = null; lock (enclaveCacheLock) { @@ -67,9 +67,9 @@ internal SqlEnclaveSession CreateSession(string attestationUrl, string serverNam } // Generates the cache key for the enclave session cache - private string GenerateCacheKey(string serverName, string attestationUrl) + private string GenerateCacheKey(string serverName, string attestationUrl, string database) { - return (serverName + attestationUrl).ToLowerInvariant(); + return (serverName + database + attestationUrl).ToLowerInvariant(); } } } 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 542af35688..2f939e16c7 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 @@ -22,9 +22,9 @@ internal class SimulatorEnclaveProvider : EnclaveProviderBase // When overridden in a derived class, looks up an existing enclave session information in the enclave session cache. // If the enclave provider doesn't implement enclave session caching, this method is expected to return null in the sqlEnclaveSession parameter. - public override void GetEnclaveSession(string servername, string attestationUrl, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) + public override void GetEnclaveSession(string servername, string attestationUrl, string database, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) { - GetEnclaveSessionHelper(servername, attestationUrl, false, out sqlEnclaveSession, out counter, out customData, out customDataLength); + GetEnclaveSessionHelper(servername, attestationUrl, database, false, out sqlEnclaveSession, out counter, out customData, out customDataLength); } // Gets the information that SqlClient subsequently uses to initiate the process of attesting the enclave and to establish a secure session with the enclave. @@ -39,7 +39,7 @@ public override SqlEnclaveAttestationParameters GetAttestationParameters(string } // 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. - public override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellmanCng clientDHKey, string attestationUrl, string servername, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter) + public override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellmanCng clientDHKey, string attestationUrl, string servername, string database, 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) @@ -49,7 +49,7 @@ public override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellma try { ThreadRetryCache.Remove(Thread.CurrentThread.ManagedThreadId.ToString()); - sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, out counter); + sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, database, out counter); if (sqlEnclaveSession == null) { @@ -88,7 +88,7 @@ public override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellma CngKey k = CngKey.Import(trustedModuleDHPublicKey, CngKeyBlobFormat.EccPublicBlob); byte[] sharedSecret = clientDHKey.DeriveKeyMaterial(k); long sessionId = BitConverter.ToInt64(enclaveSessionHandle, 0); - sqlEnclaveSession = AddEnclaveSessionToCache(attestationUrl, servername, sharedSecret, sessionId, out counter); + sqlEnclaveSession = AddEnclaveSessionToCache(attestationUrl, servername, database, sharedSecret, sessionId, out counter); } else { @@ -107,10 +107,11 @@ public override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellma /// /// The name of the SQL Server instance containing the enclave. /// The endpoint of an attestation service, SqlClient contacts to attest the enclave. + /// The database that SqlClient contacts to. /// The session to be invalidated. - public override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSessionToInvalidate) + public override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, string database, SqlEnclaveSession enclaveSessionToInvalidate) { - InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, enclaveSessionToInvalidate); + InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, database, enclaveSessionToInvalidate); } } } 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 ccf4fe889c..a52b276b8d 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 @@ -16,11 +16,12 @@ internal abstract partial class SqlColumnEncryptionEnclaveProvider /// A Diffie-Hellman algorithm object encapsulating a client-side key pair. /// The endpoint of an attestation service for attesting the enclave. /// The name of the SQL Server instance containing the enclave. + /// The database that SqlClient contacts to. /// The set of extra data needed for attestating the enclave. /// 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, string attestationUrl, string servername, byte[] customData, int customDataLength, + internal abstract void CreateEnclaveSession(byte[] enclaveAttestationInfo, ECDiffieHellmanCng clientDiffieHellmanKey, string attestationUrl, string servername, string database, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter); } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionEnclaveProvider.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionEnclaveProvider.cs index 79ba91de7b..5c039128c1 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionEnclaveProvider.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionEnclaveProvider.cs @@ -8,12 +8,12 @@ namespace Microsoft.Data.SqlClient internal abstract partial class SqlColumnEncryptionEnclaveProvider { /// - internal abstract void GetEnclaveSession(string serverName, string attestationUrl, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength); + internal abstract void GetEnclaveSession(string serverName, string attestationUrl, string database, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength); /// internal abstract SqlEnclaveAttestationParameters GetAttestationParameters(string attestationUrl, byte[] customData, int customDataLength); /// - internal abstract void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSession); + internal abstract void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, string database, SqlEnclaveSession enclaveSession); } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs index a862d74bcf..bc8c668895 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -2164,7 +2164,7 @@ private void CreateLocalCompletionTask(CommandBehavior behavior, object stateObj if (ShouldUseEnclaveBasedWorkflow && this.enclavePackage != null) { EnclaveDelegate.Instance.InvalidateEnclaveSession(this._activeConnection.AttestationProtocol, this._activeConnection.Parser.EnclaveType, - this._activeConnection.DataSource, this._activeConnection.EnclaveAttestationUrl, + this._activeConnection.DataSource, this._activeConnection.EnclaveAttestationUrl, this._activeConnection.Database, this.enclavePackage.EnclaveSession); } @@ -3483,8 +3483,9 @@ private SqlDataReader TryFetchInputParameterEncryptionInfo(int timeout, string enclaveType = this._activeConnection.Parser.EnclaveType; string dataSource = this._activeConnection.DataSource; string enclaveAttestationUrl = this._activeConnection.EnclaveAttestationUrl; + string database = this._activeConnection.Database; SqlEnclaveSession sqlEnclaveSession = null; - EnclaveDelegate.Instance.GetEnclaveSession(attestationProtocol, enclaveType, dataSource, enclaveAttestationUrl, true, out sqlEnclaveSession, out customData, out customDataLength); + EnclaveDelegate.Instance.GetEnclaveSession(attestationProtocol, enclaveType, dataSource, enclaveAttestationUrl, database, true, out sqlEnclaveSession, out customData, out customDataLength); if (sqlEnclaveSession == null) { enclaveAttestationParameters = EnclaveDelegate.Instance.GetAttestationParameters(attestationProtocol, enclaveType, enclaveAttestationUrl, customData, customDataLength); @@ -4010,8 +4011,9 @@ private void ReadDescribeEncryptionParameterResults(SqlDataReader ds, ReadOnlyDi string enclaveType = this._activeConnection.Parser.EnclaveType; string dataSource = this._activeConnection.DataSource; string enclaveAttestationUrl = this._activeConnection.EnclaveAttestationUrl; + string database = this._activeConnection.Database; - EnclaveDelegate.Instance.CreateEnclaveSession(attestationProtocol, enclaveType, dataSource, enclaveAttestationUrl, attestationInfo, enclaveAttestationParameters, customData, customDataLength); + EnclaveDelegate.Instance.CreateEnclaveSession(attestationProtocol, enclaveType, dataSource, enclaveAttestationUrl, database, attestationInfo, enclaveAttestationParameters, customData, customDataLength); enclaveAttestationParameters = null; attestationInfoRead = true; } @@ -4125,7 +4127,7 @@ internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior if (ShouldUseEnclaveBasedWorkflow && this.enclavePackage != null) { EnclaveDelegate.Instance.InvalidateEnclaveSession(this._activeConnection.AttestationProtocol, this._activeConnection.Parser.EnclaveType, - this._activeConnection.DataSource, this._activeConnection.EnclaveAttestationUrl, this.enclavePackage.EnclaveSession); + this._activeConnection.DataSource, this._activeConnection.EnclaveAttestationUrl, this._activeConnection.Database, this.enclavePackage.EnclaveSession); } return RunExecuteReader(cmdBehavior, runBehavior, returnStream, null, TdsParserStaticMethods.GetRemainingTimeout(timeout, firstAttemptStart), out task, out usedCache, isAsync, inRetry: true, method: method); @@ -4168,7 +4170,7 @@ internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior if (ShouldUseEnclaveBasedWorkflow && this.enclavePackage != null) { EnclaveDelegate.Instance.InvalidateEnclaveSession(this._activeConnection.AttestationProtocol, this._activeConnection.Parser.EnclaveType, - this._activeConnection.DataSource, this._activeConnection.EnclaveAttestationUrl, this.enclavePackage.EnclaveSession); + this._activeConnection.DataSource, this._activeConnection.EnclaveAttestationUrl, this._activeConnection.Database, this.enclavePackage.EnclaveSession); } return RunExecuteReader(cmdBehavior, runBehavior, returnStream, null, TdsParserStaticMethods.GetRemainingTimeout(timeout, firstAttemptStart), out task, out usedCache, isAsync, inRetry: true, method: method); @@ -4275,7 +4277,7 @@ private void GenerateEnclavePackage() { this.enclavePackage = EnclaveDelegate.Instance.GenerateEnclavePackage(attestationProtocol, keysToBeSentToEnclave, this.CommandText, enclaveType, this._activeConnection.DataSource, - this._activeConnection.EnclaveAttestationUrl); + this._activeConnection.EnclaveAttestationUrl, this._activeConnection.Database); } catch (EnclaveDelegate.RetryableEnclaveQueryExecutionException) { 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.NetCoreApp.cs index 207c5ef11a..24fdd4a3c1 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.NetCoreApp.cs @@ -86,9 +86,9 @@ internal abstract class VirtualizationBasedSecurityEnclaveProviderBase : Enclave // When overridden in a derived class, looks up an existing enclave session information in the enclave session cache. // If the enclave provider doesn't implement enclave session caching, this method is expected to return null in the sqlEnclaveSession parameter. - internal override void GetEnclaveSession(string servername, string attestationUrl, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) + internal override void GetEnclaveSession(string servername, string attestationUrl, string database, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) { - GetEnclaveSessionHelper(servername, attestationUrl, false, out sqlEnclaveSession, out counter, out customData, out customDataLength); + GetEnclaveSessionHelper(servername, attestationUrl, database, false, out sqlEnclaveSession, out counter, out customData, out customDataLength); } // Gets the information that SqlClient subsequently uses to initiate the process of attesting the enclave and to establish a secure session with the enclave. @@ -101,14 +101,14 @@ internal override SqlEnclaveAttestationParameters GetAttestationParameters(strin } // 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, string attestationUrl, string servername, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter) + internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellmanCng clientDHKey, string attestationUrl, string servername, string database, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter) { sqlEnclaveSession = null; counter = 0; try { ThreadRetryCache.Remove(Thread.CurrentThread.ManagedThreadId.ToString()); - sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, out counter); + sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, database, out counter); if (sqlEnclaveSession == null) { if (!string.IsNullOrEmpty(attestationUrl)) @@ -126,7 +126,7 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell byte[] sharedSecret = GetSharedSecret(info.Identity, info.EnclaveDHInfo, clientDHKey); // add session to cache - sqlEnclaveSession = AddEnclaveSessionToCache(attestationUrl, servername, sharedSecret, info.SessionId, out counter); + sqlEnclaveSession = AddEnclaveSessionToCache(attestationUrl, servername, database, sharedSecret, info.SessionId, out counter); } else { @@ -141,9 +141,9 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell } // When overridden in a derived class, looks up and evicts an enclave session from the enclave session cache, if the provider implements session caching. - internal override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSessionToInvalidate) + internal override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, string database, SqlEnclaveSession enclaveSessionToInvalidate) { - InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, enclaveSessionToInvalidate); + InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, database, enclaveSessionToInvalidate); } #endregion diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/AzureAttestationBasedEnclaveProvider.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/AzureAttestationBasedEnclaveProvider.cs index dea4db7680..daba8aa7f8 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/AzureAttestationBasedEnclaveProvider.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/AzureAttestationBasedEnclaveProvider.cs @@ -65,9 +65,9 @@ internal class AzureAttestationEnclaveProvider : EnclaveProviderBase #region Internal methods // When overridden in a derived class, looks up an existing enclave session information in the enclave session cache. // If the enclave provider doesn't implement enclave session caching, this method is expected to return null in the sqlEnclaveSession parameter. - internal override void GetEnclaveSession(string servername, string attestationUrl, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) + internal override void GetEnclaveSession(string servername, string attestationUrl, string database, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) { - GetEnclaveSessionHelper(servername, attestationUrl, generateCustomData, out sqlEnclaveSession, out counter, out customData, out customDataLength); + GetEnclaveSessionHelper(servername, attestationUrl, database, generateCustomData, out sqlEnclaveSession, out counter, out customData, out customDataLength); } // Gets the information that SqlClient subsequently uses to initiate the process of attesting the enclave and to establish a secure session with the enclave. @@ -81,14 +81,14 @@ internal override SqlEnclaveAttestationParameters GetAttestationParameters(strin } // 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, string attestationUrl, string servername, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter) + internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellmanCng clientDHKey, string attestationUrl, string servername, string database, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter) { sqlEnclaveSession = null; counter = 0; try { ThreadRetryCache.Remove(Thread.CurrentThread.ManagedThreadId.ToString()); - sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, out counter); + sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, database, out counter); if (sqlEnclaveSession == null) { if (!string.IsNullOrEmpty(attestationUrl) && customData != null && customDataLength > 0) @@ -107,7 +107,7 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell byte[] sharedSecret = GetSharedSecret(attestInfo.Identity, nonce, attestInfo.EnclaveType, attestInfo.EnclaveDHInfo, clientDHKey); // add session to cache - sqlEnclaveSession = AddEnclaveSessionToCache(attestationUrl, servername, sharedSecret, attestInfo.SessionId, out counter); + sqlEnclaveSession = AddEnclaveSessionToCache(attestationUrl, servername, database, sharedSecret, attestInfo.SessionId, out counter); } else { @@ -126,9 +126,9 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell } // When overridden in a derived class, looks up and evicts an enclave session from the enclave session cache, if the provider implements session caching. - internal override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSessionToInvalidate) + internal override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, string database, SqlEnclaveSession enclaveSessionToInvalidate) { - InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, enclaveSessionToInvalidate); + InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, database, enclaveSessionToInvalidate); } #endregion diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveDelegate.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveDelegate.cs index 4201b3545a..8fc1b9d493 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveDelegate.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveDelegate.cs @@ -42,8 +42,9 @@ private EnclaveDelegate() { } /// enclave type /// server name /// url for attestation endpoint + /// The database that SqlClient contacts to. /// - internal EnclavePackage GenerateEnclavePackage(SqlConnectionAttestationProtocol attestationProtocol, Dictionary keysTobeSentToEnclave, string queryText, string enclaveType, string serverName, string enclaveAttestationUrl) + internal EnclavePackage GenerateEnclavePackage(SqlConnectionAttestationProtocol attestationProtocol, Dictionary keysTobeSentToEnclave, string queryText, string enclaveType, string serverName, string enclaveAttestationUrl, string database) { SqlEnclaveSession sqlEnclaveSession = null; @@ -52,7 +53,7 @@ internal EnclavePackage GenerateEnclavePackage(SqlConnectionAttestationProtocol int dummyCustomDataLength; try { - GetEnclaveSession(attestationProtocol, enclaveType, serverName, enclaveAttestationUrl, false, out sqlEnclaveSession, out counter, out dummyCustomData, out dummyCustomDataLength, throwIfNull: true); + GetEnclaveSession(attestationProtocol, enclaveType, serverName, enclaveAttestationUrl, database, false, out sqlEnclaveSession, out counter, out dummyCustomData, out dummyCustomDataLength, throwIfNull: true); } catch (Exception e) { @@ -69,22 +70,22 @@ internal EnclavePackage GenerateEnclavePackage(SqlConnectionAttestationProtocol return new EnclavePackage(byteArrayToBeSentToEnclave, sqlEnclaveSession); } - internal void InvalidateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string EnclaveAttestationUrl, SqlEnclaveSession enclaveSession) + internal void InvalidateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string EnclaveAttestationUrl, string database, SqlEnclaveSession enclaveSession) { SqlColumnEncryptionEnclaveProvider sqlColumnEncryptionEnclaveProvider = GetEnclaveProvider(attestationProtocol, enclaveType); - sqlColumnEncryptionEnclaveProvider.InvalidateEnclaveSession(serverName, EnclaveAttestationUrl, enclaveSession); + sqlColumnEncryptionEnclaveProvider.InvalidateEnclaveSession(serverName, EnclaveAttestationUrl, database, enclaveSession); } - internal void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string enclaveAttestationUrl, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out byte[] customData, out int customDataLength) + internal void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string enclaveAttestationUrl, string database, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out byte[] customData, out int customDataLength) { long counter; - GetEnclaveSession(attestationProtocol, enclaveType, serverName, enclaveAttestationUrl, generateCustomData, out sqlEnclaveSession, out counter, out customData, out customDataLength, throwIfNull: false); + GetEnclaveSession(attestationProtocol, enclaveType, serverName, enclaveAttestationUrl, database, generateCustomData, out sqlEnclaveSession, out counter, out customData, out customDataLength, throwIfNull: false); } - private void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string enclaveAttestationUrl, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength, bool throwIfNull) + private void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string enclaveAttestationUrl, string database, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength, bool throwIfNull) { SqlColumnEncryptionEnclaveProvider sqlColumnEncryptionEnclaveProvider = GetEnclaveProvider(attestationProtocol, enclaveType); - sqlColumnEncryptionEnclaveProvider.GetEnclaveSession(serverName, enclaveAttestationUrl, generateCustomData, out sqlEnclaveSession, out counter, out customData, out customDataLength); + sqlColumnEncryptionEnclaveProvider.GetEnclaveSession(serverName, enclaveAttestationUrl, database, generateCustomData, out sqlEnclaveSession, out counter, out customData, out customDataLength); if (throwIfNull && sqlEnclaveSession == null) { @@ -159,11 +160,12 @@ private byte[] GetUintBytes(string enclaveType, int intValue, string variableNam /// enclave type /// servername /// attestation url for attestation service endpoint + /// The database that SqlClient contacts to. /// attestation info from SQL Server /// attestation parameters /// A set of extra data needed for attestating the enclave. /// The length of the extra data needed for attestating the enclave. - internal void CreateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string attestationUrl, + internal void CreateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string attestationUrl, string database, byte[] attestationInfo, SqlEnclaveAttestationParameters attestationParameters, byte[] customData, int customDataLength) { @@ -174,14 +176,14 @@ internal void CreateEnclaveSession(SqlConnectionAttestationProtocol attestationP SqlEnclaveSession sqlEnclaveSession = null; byte[] dummyCustomData = null; int dummyCustomDataLength; - sqlColumnEncryptionEnclaveProvider.GetEnclaveSession(serverName, attestationUrl, false, out sqlEnclaveSession, out counter, out dummyCustomData, out dummyCustomDataLength); + sqlColumnEncryptionEnclaveProvider.GetEnclaveSession(serverName, attestationUrl, database, false, out sqlEnclaveSession, out counter, out dummyCustomData, out dummyCustomDataLength); if (sqlEnclaveSession != null) { return; } - sqlColumnEncryptionEnclaveProvider.CreateEnclaveSession(attestationInfo, attestationParameters.ClientDiffieHellmanKey, attestationUrl, serverName, customData, customDataLength, out sqlEnclaveSession, out counter); + sqlColumnEncryptionEnclaveProvider.CreateEnclaveSession(attestationInfo, attestationParameters.ClientDiffieHellmanKey, attestationUrl, serverName, database, customData, customDataLength, out sqlEnclaveSession, out counter); if (sqlEnclaveSession == null) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveProviderBase.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveProviderBase.cs index 03a49f34f1..555dce7bb9 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveProviderBase.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveProviderBase.cs @@ -89,11 +89,11 @@ internal abstract class EnclaveProviderBase : SqlColumnEncryptionEnclaveProvider #region Public methods // Helper method to get the enclave session from the cache if present - protected void GetEnclaveSessionHelper(string servername, string attestationUrl, bool shouldGenerateNonce, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) + protected void GetEnclaveSessionHelper(string servername, string attestationUrl, string database, bool shouldGenerateNonce, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) { customData = null; customDataLength = 0; - sqlEnclaveSession = SessionCache.GetEnclaveSession(servername, attestationUrl, out counter); + sqlEnclaveSession = SessionCache.GetEnclaveSession(servername, attestationUrl, database, out counter); if (sqlEnclaveSession == null) { @@ -128,7 +128,7 @@ protected void GetEnclaveSessionHelper(string servername, string attestationUrl, { // While the current thread is waiting for event to be signaled and in the meanwhile we already completed the attestation on different thread // then we need to signal the event here - sqlEnclaveSession = SessionCache.GetEnclaveSession(servername, attestationUrl, out counter); + sqlEnclaveSession = SessionCache.GetEnclaveSession(servername, attestationUrl, database, out counter); if (sqlEnclaveSession != null && !sameThreadRetry) { lock (lockUpdateSessionLock) @@ -194,21 +194,21 @@ protected void UpdateEnclaveSessionLockStatus(SqlEnclaveSession sqlEnclaveSessio } // Helper method to remove the enclave session from the cache - protected void InvalidateEnclaveSessionHelper(string servername, string attestationUrl, SqlEnclaveSession enclaveSessionToInvalidate) + protected void InvalidateEnclaveSessionHelper(string servername, string attestationUrl, string database, SqlEnclaveSession enclaveSessionToInvalidate) { - SessionCache.InvalidateSession(servername, attestationUrl, enclaveSessionToInvalidate); + SessionCache.InvalidateSession(servername, attestationUrl, database, enclaveSessionToInvalidate); } // Helper method for getting the enclave session from the session cache - protected SqlEnclaveSession GetEnclaveSessionFromCache(string attestationUrl, string servername, out long counter) + protected SqlEnclaveSession GetEnclaveSessionFromCache(string attestationUrl, string servername, string database, out long counter) { - return SessionCache.GetEnclaveSession(servername, attestationUrl, out counter); + return SessionCache.GetEnclaveSession(servername, attestationUrl, database, out counter); } // Helper method for adding the enclave session to the session cache - protected SqlEnclaveSession AddEnclaveSessionToCache(string attestationUrl, string servername, byte[] sharedSecret, long sessionId, out long counter) + protected SqlEnclaveSession AddEnclaveSessionToCache(string attestationUrl, string servername, string database, byte[] sharedSecret, long sessionId, out long counter) { - return SessionCache.CreateSession(attestationUrl, servername, sharedSecret, sessionId, out counter); + return SessionCache.CreateSession(attestationUrl, servername, database, sharedSecret, sessionId, out counter); } } #endregion diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs index 5cf0590d06..d0906c6598 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs @@ -22,23 +22,23 @@ internal class EnclaveSessionCache private static int enclaveCacheTimeOutInHours = 8; // Retrieves a SqlEnclaveSession from the cache - internal SqlEnclaveSession GetEnclaveSession(string servername, string attestationUrl, out long counter) + internal SqlEnclaveSession GetEnclaveSession(string servername, string attestationUrl, string database, out long counter) { - string cacheKey = GenerateCacheKey(servername, attestationUrl); + string cacheKey = GenerateCacheKey(servername, attestationUrl, database); SqlEnclaveSession enclaveSession = enclaveMemoryCache[cacheKey] as SqlEnclaveSession; counter = Interlocked.Increment(ref _counter); return enclaveSession; } // Invalidates a SqlEnclaveSession entry in the cache - internal void InvalidateSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSessionToInvalidate) + internal void InvalidateSession(string serverName, string enclaveAttestationUrl, string database, SqlEnclaveSession enclaveSessionToInvalidate) { - string cacheKey = GenerateCacheKey(serverName, enclaveAttestationUrl); + string cacheKey = GenerateCacheKey(serverName, enclaveAttestationUrl, database); lock (enclaveCacheLock) { long counter; - SqlEnclaveSession enclaveSession = GetEnclaveSession(serverName, enclaveAttestationUrl, out counter); + SqlEnclaveSession enclaveSession = GetEnclaveSession(serverName, enclaveAttestationUrl, database, out counter); if (enclaveSession != null && enclaveSession.SessionId == enclaveSessionToInvalidate.SessionId) { @@ -52,9 +52,9 @@ internal void InvalidateSession(string serverName, string enclaveAttestationUrl, } // Creates a new SqlEnclaveSession and adds it to the cache - internal SqlEnclaveSession CreateSession(string attestationUrl, string serverName, byte[] sharedSecret, long sessionId, out long counter) + internal SqlEnclaveSession CreateSession(string attestationUrl, string serverName, string database, byte[] sharedSecret, long sessionId, out long counter) { - string cacheKey = GenerateCacheKey(serverName, attestationUrl); + string cacheKey = GenerateCacheKey(serverName, attestationUrl, database); SqlEnclaveSession enclaveSession = null; lock (enclaveCacheLock) { @@ -67,9 +67,9 @@ internal SqlEnclaveSession CreateSession(string attestationUrl, string serverNam } // Generates the cache key for the enclave session cache - private string GenerateCacheKey(string serverName, string attestationUrl) + private string GenerateCacheKey(string serverName, string attestationUrl, string database) { - return (serverName + attestationUrl).ToLowerInvariant(); + return (serverName + database + attestationUrl).ToLowerInvariant(); } } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs index cf9af48632..255e9d2593 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs @@ -22,9 +22,9 @@ internal class SimulatorEnclaveProvider : EnclaveProviderBase // When overridden in a derived class, looks up an existing enclave session information in the enclave session cache. // If the enclave provider doesn't implement enclave session caching, this method is expected to return null in the sqlEnclaveSession parameter. - internal override void GetEnclaveSession(string servername, string attestationUrl, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) + internal override void GetEnclaveSession(string servername, string attestationUrl, string database, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) { - GetEnclaveSessionHelper(servername, attestationUrl, false, out sqlEnclaveSession, out counter, out customData, out customDataLength); + GetEnclaveSessionHelper(servername, attestationUrl, database, false, out sqlEnclaveSession, out counter, out customData, out customDataLength); } // Gets the information that SqlClient subsequently uses to initiate the process of attesting the enclave and to establish a secure session with the enclave. @@ -39,7 +39,7 @@ internal override SqlEnclaveAttestationParameters GetAttestationParameters(strin } // 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, string attestationUrl, string servername, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter) + internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellmanCng clientDHKey, string attestationUrl, string servername, string database, 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) @@ -49,7 +49,7 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell try { ThreadRetryCache.Remove(Thread.CurrentThread.ManagedThreadId.ToString()); - sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, out counter); + sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, database, out counter); if (sqlEnclaveSession == null) { @@ -88,7 +88,7 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell CngKey k = CngKey.Import(trustedModuleDHPublicKey, CngKeyBlobFormat.EccPublicBlob); byte[] sharedSecret = clientDHKey.DeriveKeyMaterial(k); long sessionId = BitConverter.ToInt64(enclaveSessionHandle, 0); - sqlEnclaveSession = AddEnclaveSessionToCache(attestationUrl, servername, sharedSecret, sessionId, out counter); + sqlEnclaveSession = AddEnclaveSessionToCache(attestationUrl, servername, database, sharedSecret, sessionId, out counter); } else { @@ -107,10 +107,11 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell /// /// The name of the SQL Server instance containing the enclave. /// The endpoint of an attestation service, SqlClient contacts to attest the enclave. + /// The database that SqlClient contacts to. /// The session to be invalidated. - internal override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSessionToInvalidate) + internal override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, string database, SqlEnclaveSession enclaveSessionToInvalidate) { - InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, enclaveSessionToInvalidate); + InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, database, enclaveSessionToInvalidate); } } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlColumnEncryptionEnclaveProvider.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlColumnEncryptionEnclaveProvider.cs index d29e7d1643..ae537e96fa 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlColumnEncryptionEnclaveProvider.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlColumnEncryptionEnclaveProvider.cs @@ -11,15 +11,15 @@ internal abstract class SqlColumnEncryptionEnclaveProvider { /// - internal abstract void GetEnclaveSession(string serverName, string attestationUrl, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength); + internal abstract void GetEnclaveSession(string serverName, string attestationUrl, string database, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength); /// internal abstract SqlEnclaveAttestationParameters GetAttestationParameters(string attestationUrl, byte[] customData, int customDataLength); /// - internal abstract void CreateEnclaveSession(byte[] enclaveAttestationInfo, ECDiffieHellmanCng clientDiffieHellmanKey, string attestationUrl, string servername, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter); + internal abstract void CreateEnclaveSession(byte[] enclaveAttestationInfo, ECDiffieHellmanCng clientDiffieHellmanKey, string attestationUrl, string servername, string database, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter); /// - internal abstract void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSession); + internal abstract void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, string database, SqlEnclaveSession enclaveSession); } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs index 09d7ba3bbe..a6d9f8429a 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -2714,7 +2714,8 @@ private bool TriggerInternalEndAndRetryIfNecessary(CommandBehavior behavior, obj if (ShouldUseEnclaveBasedWorkflow && this.enclavePackage != null) { - EnclaveDelegate.Instance.InvalidateEnclaveSession(this._activeConnection.AttestationProtocol, this._activeConnection.Parser.EnclaveType, this._activeConnection.DataSource, this._activeConnection.EnclaveAttestationUrl, this.enclavePackage.EnclaveSession); + EnclaveDelegate.Instance.InvalidateEnclaveSession(this._activeConnection.AttestationProtocol, this._activeConnection.Parser.EnclaveType, + this._activeConnection.DataSource, this._activeConnection.EnclaveAttestationUrl, this._activeConnection.Database, this.enclavePackage.EnclaveSession); } try @@ -4257,8 +4258,9 @@ private SqlDataReader TryFetchInputParameterEncryptionInfo(int timeout, string enclaveType = this._activeConnection.Parser.EnclaveType; string dataSource = this._activeConnection.DataSource; string enclaveAttestationUrl = this._activeConnection.EnclaveAttestationUrl; + string database = this._activeConnection.Database; SqlEnclaveSession sqlEnclaveSession = null; - EnclaveDelegate.Instance.GetEnclaveSession(attestationProtocol, enclaveType, dataSource, enclaveAttestationUrl, true, out sqlEnclaveSession, out customData, out customDataLength); + EnclaveDelegate.Instance.GetEnclaveSession(attestationProtocol, enclaveType, dataSource, enclaveAttestationUrl, database, true, out sqlEnclaveSession, out customData, out customDataLength); if (sqlEnclaveSession == null) { this.enclaveAttestationParameters = EnclaveDelegate.Instance.GetAttestationParameters(attestationProtocol, enclaveType, enclaveAttestationUrl, customData, customDataLength); @@ -4794,8 +4796,9 @@ private void ReadDescribeEncryptionParameterResults(SqlDataReader ds, ReadOnlyDi string enclaveType = this._activeConnection.Parser.EnclaveType; string dataSource = this._activeConnection.DataSource; string enclaveAttestationUrl = this._activeConnection.EnclaveAttestationUrl; + string database = this._activeConnection.Database; - EnclaveDelegate.Instance.CreateEnclaveSession(attestationProtocol, enclaveType, dataSource, enclaveAttestationUrl, attestationInfo, enclaveAttestationParameters, customData, customDataLength); + EnclaveDelegate.Instance.CreateEnclaveSession(attestationProtocol, enclaveType, dataSource, enclaveAttestationUrl, database, attestationInfo, enclaveAttestationParameters, customData, customDataLength); enclaveAttestationParameters = null; attestationInfoRead = true; } @@ -4930,7 +4933,7 @@ internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior if (ShouldUseEnclaveBasedWorkflow && this.enclavePackage != null) { EnclaveDelegate.Instance.InvalidateEnclaveSession(this._activeConnection.AttestationProtocol, this._activeConnection.Parser.EnclaveType, - this._activeConnection.DataSource, this._activeConnection.EnclaveAttestationUrl, this.enclavePackage.EnclaveSession); + this._activeConnection.DataSource, this._activeConnection.EnclaveAttestationUrl, this._activeConnection.Database, this.enclavePackage.EnclaveSession); } return RunExecuteReader(cmdBehavior, runBehavior, returnStream, method, null, TdsParserStaticMethods.GetRemainingTimeout(timeout, firstAttemptStart), out task, out usedCache, async, inRetry: true); @@ -4973,7 +4976,7 @@ internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior if (ShouldUseEnclaveBasedWorkflow && this.enclavePackage != null) { EnclaveDelegate.Instance.InvalidateEnclaveSession(this._activeConnection.AttestationProtocol, this._activeConnection.Parser.EnclaveType, - this._activeConnection.DataSource, this._activeConnection.EnclaveAttestationUrl, this.enclavePackage.EnclaveSession); + this._activeConnection.DataSource, this._activeConnection.EnclaveAttestationUrl, this._activeConnection.Database, this.enclavePackage.EnclaveSession); } return RunExecuteReader(cmdBehavior, runBehavior, returnStream, method, null, TdsParserStaticMethods.GetRemainingTimeout(timeout, firstAttemptStart), out task, out usedCache, async, inRetry: true); @@ -5118,7 +5121,7 @@ private void GenerateEnclavePackage() { this.enclavePackage = EnclaveDelegate.Instance.GenerateEnclavePackage(attestationProtocol, keysToBeSentToEnclave, this.CommandText, enclaveType, this._activeConnection.DataSource, - this._activeConnection.EnclaveAttestationUrl); + this._activeConnection.EnclaveAttestationUrl, this._activeConnection.Database); } catch (EnclaveDelegate.RetryableEnclaveQueryExecutionException) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs index 73da211f7e..6911a13fb6 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs @@ -86,9 +86,9 @@ internal abstract class VirtualizationBasedSecurityEnclaveProviderBase : Enclave // When overridden in a derived class, looks up an existing enclave session information in the enclave session cache. // If the enclave provider doesn't implement enclave session caching, this method is expected to return null in the sqlEnclaveSession parameter. - internal override void GetEnclaveSession(string servername, string attestationUrl, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) + internal override void GetEnclaveSession(string servername, string attestationUrl, string database, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength) { - GetEnclaveSessionHelper(servername, attestationUrl, false, out sqlEnclaveSession, out counter, out customData, out customDataLength); + GetEnclaveSessionHelper(servername, attestationUrl, database, false, out sqlEnclaveSession, out counter, out customData, out customDataLength); } // Gets the information that SqlClient subsequently uses to initiate the process of attesting the enclave and to establish a secure session with the enclave. @@ -102,14 +102,14 @@ internal override SqlEnclaveAttestationParameters GetAttestationParameters(strin } // 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, string attestationUrl, string servername, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter) + internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellmanCng clientDHKey, string attestationUrl, string servername, string database, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter) { sqlEnclaveSession = null; counter = 0; try { ThreadRetryCache.Remove(Thread.CurrentThread.ManagedThreadId.ToString()); - sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, out counter); + sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, database, out counter); if (sqlEnclaveSession == null) { if (!string.IsNullOrEmpty(attestationUrl)) @@ -127,7 +127,7 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell byte[] sharedSecret = GetSharedSecret(info.Identity, info.EnclaveDHInfo, clientDHKey); // add session to cache - sqlEnclaveSession = AddEnclaveSessionToCache(attestationUrl, servername, sharedSecret, info.SessionId, out counter); + sqlEnclaveSession = AddEnclaveSessionToCache(attestationUrl, servername, database, sharedSecret, info.SessionId, out counter); } else { @@ -142,9 +142,9 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell } // When overridden in a derived class, looks up and evicts an enclave session from the enclave session cache, if the provider implements session caching. - internal override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSessionToInvalidate) + internal override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, string database, SqlEnclaveSession enclaveSessionToInvalidate) { - InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, enclaveSessionToInvalidate); + InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, database, enclaveSessionToInvalidate); } #endregion From 3e6edcdb0c8bf108fc419c262db6b0e8cf8dd4bf Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Thu, 18 Jun 2020 18:46:23 -0700 Subject: [PATCH 02/12] Update xml --- .../SqlColumnEncryptionEnclaveProvider.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml index c85f90fc84..d00904b93f 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml @@ -21,6 +21,7 @@ the enclave attestation protocol as well as the logic for creating and caching e A Diffie-Hellman algorithm object that encapsulates a client-side key pair. The endpoint of an attestation service for attesting the enclave. The name of the SQL Server instance containing the enclave. + The database that SqlClient contacts to. The set of extra data needed for attestating the enclave. The length of the extra data needed for attestating the enclave. The requested enclave session or if the provider doesn't implement session caching. @@ -39,6 +40,7 @@ the enclave attestation protocol as well as the logic for creating and caching e The name of the SQL Server instance containing the enclave. The endpoint of an attestation service, SqlClient contacts to attest the enclave. + The database that SqlClient contacts to. to indicate that a set of extra data needs to be generated for attestation; otherwise, . When this method returns, the requested enclave session or if the provider doesn't implement session caching. This parameter is treated as uninitialized. 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. @@ -51,6 +53,7 @@ the enclave attestation protocol as well as the logic for creating and caching e The name of the SQL Server instance containing the enclave. The endpoint of an attestation service, SqlClient contacts to attest the enclave. + The database that SqlClient contacts to. The session to be invalidated. When overridden in a derived class, looks up and evicts an enclave session from the enclave session cache, if the provider implements session caching. To be added. From 70ca7696a4129516cbcb9c0754d1019460b6e4fc Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Thu, 2 Jul 2020 15:21:22 -0700 Subject: [PATCH 03/12] Add test targeting Azure Database with enclave-enabled --- .../EnclaveAzureDatabaseTests.cs | 182 ++++++++++++++++++ .../SQLSetupStrategyAzureKeyVault.cs | 2 +- .../TestFixtures/Setup/AkvColumnMasterKey.cs | 8 +- .../TestFixtures/Setup/CspColumnMasterKey.cs | 8 +- .../ManualTests/DataCommon/DataTestUtility.cs | 7 + ....Data.SqlClient.ManualTesting.Tests.csproj | 1 + 6 files changed, 202 insertions(+), 6 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/EnclaveAzureDatabaseTests.cs diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/EnclaveAzureDatabaseTests.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/EnclaveAzureDatabaseTests.cs new file mode 100644 index 0000000000..ef3f30551a --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/EnclaveAzureDatabaseTests.cs @@ -0,0 +1,182 @@ +// 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; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Threading.Tasks; +using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider; +using Microsoft.Data.SqlClient.ManualTesting.Tests; +using Xunit; +using Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted +{ + public class EnclaveAzureDatabaseTests : IDisposable + { + private ColumnMasterKey akvColumnMasterKey; + private ColumnEncryptionKey akvColumnEncryptionKey; + private SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider; + private List databaseObjects = new List(); + private List connStrings = new List(); + + public EnclaveAzureDatabaseTests() + { + if (DataTestUtility.IsEnclaveAzureDatabaseSetup() && DataTestUtility.EnclaveEnabled) + { + // Initialize AKV provider + sqlColumnEncryptionAzureKeyVaultProvider = new SqlColumnEncryptionAzureKeyVaultProvider(AADUtility.AzureActiveDirectoryAuthenticationCallback); + + // Register AKV provider + SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders: new Dictionary(capacity: 1, comparer: StringComparer.OrdinalIgnoreCase) + { + { SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, sqlColumnEncryptionAzureKeyVaultProvider} + }); + + akvColumnMasterKey = new AkvColumnMasterKey(DatabaseHelper.GenerateUniqueName("AKVCMK"), akvUrl: DataTestUtility.AKVUrl, sqlColumnEncryptionAzureKeyVaultProvider, DataTestUtility.EnclaveEnabled); + databaseObjects.Add(akvColumnMasterKey); + + akvColumnEncryptionKey= new ColumnEncryptionKey(DatabaseHelper.GenerateUniqueName("AKVCEK"), + akvColumnMasterKey, + sqlColumnEncryptionAzureKeyVaultProvider); + databaseObjects.Add(akvColumnEncryptionKey); + + SqlConnectionStringBuilder connString1 = new SqlConnectionStringBuilder(DataTestUtility.EnclaveAzureDatabaseConnString); + connString1.InitialCatalog = "testdb001"; + + SqlConnectionStringBuilder connString2 = new SqlConnectionStringBuilder(DataTestUtility.EnclaveAzureDatabaseConnString); + connString2.InitialCatalog = "testdb002"; + + connStrings.Add(connString1.ToString()); + connStrings.Add(connString2.ToString()); + + foreach (string connString in connStrings) + { + using (SqlConnection connection = new SqlConnection(connString)) + { + connection.Open(); + databaseObjects.ForEach(o => o.Create(connection)); + } + } + } + } + + [PlatformSpecific(TestPlatforms.Windows)] + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsEnclaveAzureDatabaseSetup))] + public void ConnectToAzureDatabaseWithEnclave() + { + if (DataTestUtility.EnclaveEnabled) + { + string tableName = DatabaseHelper.GenerateUniqueName("AzureTable"); + + foreach (string connString in connStrings) + { + using (SqlConnection sqlConnection = new SqlConnection(connString)) + { + sqlConnection.Open(); + + Customer customer = new Customer(1, @"Microsoft", @"Corporation"); + + try + { + CreateTable(sqlConnection, akvColumnEncryptionKey.Name, tableName); + InsertData(sqlConnection, tableName, customer); + VerifyData(sqlConnection, tableName, customer); + } + finally + { + DropTableIfExists(sqlConnection, tableName); + } + } + } + } + } + + private void CreateTable(SqlConnection sqlConnection, string cekName, string tableName) + { + string ColumnEncryptionAlgorithmName = @"AEAD_AES_256_CBC_HMAC_SHA_256"; + string sql = + $@"CREATE TABLE [dbo].[{tableName}] + ( + [CustomerId] [int] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = '{ColumnEncryptionAlgorithmName}'), + [FirstName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = '{ColumnEncryptionAlgorithmName}'), + [LastName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = '{ColumnEncryptionAlgorithmName}') + )"; + using (SqlCommand command = sqlConnection.CreateCommand()) + { + command.CommandText = sql; + command.ExecuteNonQuery(); + } + } + + private void InsertData(SqlConnection sqlConnection, string tableName, Customer newCustomer) + { + string insertSql = $"INSERT INTO [{tableName}] (CustomerId, FirstName, LastName) VALUES (@CustomerId, @FirstName, @LastName);"; + using (SqlTransaction sqlTransaction = sqlConnection.BeginTransaction()) + using (SqlCommand sqlCommand = new SqlCommand(insertSql, + connection: sqlConnection, transaction: sqlTransaction, + columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled)) + { + sqlCommand.Parameters.AddWithValue(@"CustomerId", newCustomer.Id); + sqlCommand.Parameters.AddWithValue(@"FirstName", newCustomer.FirstName); + sqlCommand.Parameters.AddWithValue(@"LastName", newCustomer.LastName); + sqlCommand.ExecuteNonQuery(); + sqlTransaction.Commit(); + } + } + + private void VerifyData(SqlConnection sqlConnection, string tableName, Customer customer) + { + // Test INPUT parameter on an encrypted parameter + using (SqlCommand sqlCommand = new SqlCommand($"SELECT CustomerId, FirstName, LastName FROM [{tableName}] WHERE FirstName = @firstName", + sqlConnection)) + { + SqlParameter customerFirstParam = sqlCommand.Parameters.AddWithValue(@"firstName", @"Microsoft"); + customerFirstParam.Direction = System.Data.ParameterDirection.Input; + customerFirstParam.ForceColumnEncryption = true; + using (SqlDataReader sqlDataReader = sqlCommand.ExecuteReader()) + { + ValidateResultSet(sqlDataReader); + } + } + } + + private void ValidateResultSet(SqlDataReader sqlDataReader) + { + Assert.True(sqlDataReader.HasRows, "We didn't find any rows."); + while (sqlDataReader.Read()) + { + Assert.True(sqlDataReader.GetInt32(0) == 1, "Employee Id didn't match"); + Assert.True(sqlDataReader.GetString(1) == @"Microsoft", "Employee FirstName didn't match."); + Assert.True(sqlDataReader.GetString(2) == @"Corporation", "Employee LastName didn't match."); + } + } + + private void DropTableIfExists(SqlConnection sqlConnection, string tableName) + { + string cmdText = $@"IF EXISTS (select * from sys.objects where name = '{tableName}') BEGIN DROP TABLE [{tableName}] END"; + using (SqlCommand command = sqlConnection.CreateCommand()) + { + command.CommandText = cmdText; + command.ExecuteNonQuery(); + } + } + + public void Dispose() + { + if (DataTestUtility.IsEnclaveAzureDatabaseSetup() && DataTestUtility.EnclaveEnabled) + { + databaseObjects.Reverse(); + foreach (string connStr in connStrings) + { + using (SqlConnection sqlConnection = new SqlConnection(connStr)) + { + sqlConnection.Open(); + databaseObjects.ForEach(o => o.Drop(sqlConnection)); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategyAzureKeyVault.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategyAzureKeyVault.cs index 288e6f069a..b144673e82 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategyAzureKeyVault.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategyAzureKeyVault.cs @@ -36,7 +36,7 @@ public SQLSetupStrategyAzureKeyVault() : base() internal override void SetupDatabase() { - ColumnMasterKey akvColumnMasterKey = new AkvColumnMasterKey(GenerateUniqueName("AKVCMK"), akvUrl: DataTestUtility.AKVUrl); + ColumnMasterKey akvColumnMasterKey = new AkvColumnMasterKey(GenerateUniqueName("AKVCMK"), akvUrl: DataTestUtility.AKVUrl, AkvStoreProvider, DataTestUtility.EnclaveEnabled); databaseObjects.Add(akvColumnMasterKey); List akvColumnEncryptionKeys = CreateColumnEncryptionKeys(akvColumnMasterKey, 2, AkvStoreProvider); 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 5f3f51f72e..a9469d79b6 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 @@ -2,16 +2,22 @@ // 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; + namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup { public class AkvColumnMasterKey : ColumnMasterKey { public override string KeyPath { get; } - public AkvColumnMasterKey(string name, string akvUrl) : base(name) + public AkvColumnMasterKey(string name, string akvUrl, SqlColumnEncryptionKeyStoreProvider akvProvider, bool allowEnclaveComputations) : base(name) { KeyStoreProviderName = @"AZURE_KEY_VAULT"; KeyPath = akvUrl; + + // For keys which allow enclave computation + byte[] cmkSign = akvProvider.SignColumnMasterKeyMetadata(akvUrl, allowEnclaveComputations); + cmkSignStr = string.Concat("0x", BitConverter.ToString(cmkSign).Replace("-", string.Empty)); } } } 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 22b31ab888..9e26b1105e 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 @@ -14,21 +14,21 @@ public class CspColumnMasterKey : ColumnMasterKey public string Thumbprint { get; } public override string KeyPath { get; } - public CspColumnMasterKey(string name, string certificateThumbprint, SqlColumnEncryptionKeyStoreProvider certStoreProvider, bool allEnclaveComputations) : base(name) + public CspColumnMasterKey(string name, string certificateThumbprint, SqlColumnEncryptionKeyStoreProvider certStoreProvider, bool allowEnclaveComputations) : base(name) { KeyStoreProviderName = @"MSSQL_CERTIFICATE_STORE"; Thumbprint = certificateThumbprint; KeyPath = string.Concat(CertificateStoreLocation.ToString(), "/", CertificateStoreName.ToString(), "/", Thumbprint); - byte[] cmkSign = certStoreProvider.SignColumnMasterKeyMetadata(KeyPath, allEnclaveComputations); + byte[] cmkSign = certStoreProvider.SignColumnMasterKeyMetadata(KeyPath, allowEnclaveComputations); cmkSignStr = string.Concat("0x", BitConverter.ToString(cmkSign).Replace("-", string.Empty)); } - public CspColumnMasterKey(string name, string providerName, string cspKeyPath, SqlColumnEncryptionKeyStoreProvider certStoreProvider, bool allEnclaveComputations) : base(name) + public CspColumnMasterKey(string name, string providerName, string cspKeyPath, SqlColumnEncryptionKeyStoreProvider certStoreProvider, bool allowEnclaveComputations) : base(name) { KeyStoreProviderName = providerName; KeyPath = cspKeyPath; - byte[] cmkSign = certStoreProvider.SignColumnMasterKeyMetadata(KeyPath, allEnclaveComputations); + byte[] cmkSign = certStoreProvider.SignColumnMasterKeyMetadata(KeyPath, allowEnclaveComputations); cmkSignStr = string.Concat("0x", BitConverter.ToString(cmkSign).Replace("-", string.Empty)); } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 1e8fa398c6..7cf7184618 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -49,6 +49,8 @@ public static class DataTestUtility public static readonly bool IsDNSCachingSupportedCR = false; // this is for the control ring public static readonly bool IsDNSCachingSupportedTR = false; // this is for the tenant ring + public static readonly string EnclaveAzureDatabaseConnString = null; + public const string UdtTestDbName = "UdtTestDb"; public const string AKVKeyName = "TestSqlClientAzureKeyVaultProvider"; private const string ManagedNetworkingAppContextSwitch = "Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows"; @@ -86,6 +88,7 @@ private class Config public string DNSCachingServerTR = null; // this is for the tenant ring public bool IsDNSCachingSupportedCR = false; // this is for the control ring public bool IsDNSCachingSupportedTR = false; // this is for the tenant ring + public string EnclaveAzureDatabaseConnString = null; } static DataTestUtility() @@ -117,6 +120,8 @@ static DataTestUtility() IsDNSCachingSupportedCR = c.IsDNSCachingSupportedCR; IsDNSCachingSupportedTR = c.IsDNSCachingSupportedTR; + EnclaveAzureDatabaseConnString = c.EnclaveAzureDatabaseConnString; + if (TracingEnabled) { TraceListener = new DataTestUtility.TraceEventListener(); @@ -284,6 +289,8 @@ public static bool IsSupportedDataClassification() public static bool IsDNSCachingSetup() => !string.IsNullOrEmpty(DNSCachingConnString); + public static bool IsEnclaveAzureDatabaseSetup() => !string.IsNullOrEmpty(EnclaveAzureDatabaseConnString); + public static bool IsUdtTestDatabasePresent() => IsDatabasePresent(UdtTestDbName); public static bool AreConnStringsSetup() 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 34bd1e6ead..afbd056adb 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 @@ -26,6 +26,7 @@ + From 56962e8973804a0679b96ee112956cf3038085c7 Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Tue, 7 Jul 2020 14:23:44 -0700 Subject: [PATCH 04/12] Update src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionEnclaveProvider.NetCoreApp.cs Co-authored-by: Cheena Malhotra --- .../SqlClient/SqlColumnEncryptionEnclaveProvider.NetCoreApp.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a52b276b8d..2a0614a8e6 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 @@ -16,7 +16,7 @@ internal abstract partial class SqlColumnEncryptionEnclaveProvider /// A Diffie-Hellman algorithm object encapsulating a client-side key pair. /// The endpoint of an attestation service for attesting the enclave. /// The name of the SQL Server instance containing the enclave. - /// The database that SqlClient contacts to. + /// The database that SqlClient contacts to request an enclave session. /// The set of extra data needed for attestating the enclave. /// 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. From 53232f2378e0f9bcc4a67e28fdf9aae687de56c2 Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Tue, 7 Jul 2020 14:24:36 -0700 Subject: [PATCH 05/12] Update src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs Extended parameter description Co-authored-by: Cheena Malhotra --- .../src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs index 255e9d2593..67737a715a 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs @@ -107,7 +107,7 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell /// /// The name of the SQL Server instance containing the enclave. /// The endpoint of an attestation service, SqlClient contacts to attest the enclave. - /// The database that SqlClient contacts to. + /// The database that SqlClient contacts to request an enclave session. /// The session to be invalidated. internal override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, string database, SqlEnclaveSession enclaveSessionToInvalidate) { From 06bfae30afdfaeb6b0d5b8cc0f24243d4865b780 Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Tue, 7 Jul 2020 14:25:10 -0700 Subject: [PATCH 06/12] Update src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveDelegate.NetStandard.cs Extended parameter description Co-authored-by: Cheena Malhotra --- .../src/Microsoft/Data/SqlClient/EnclaveDelegate.NetStandard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveDelegate.NetStandard.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveDelegate.NetStandard.cs index b6083296f9..a875511ce3 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveDelegate.NetStandard.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveDelegate.NetStandard.cs @@ -25,7 +25,7 @@ internal byte[] GetSerializedAttestationParameters( /// enclave type /// servername /// attestation url for attestation service endpoint - /// The database that SqlClient contacts to. + /// The database that SqlClient contacts to request an enclave session. /// attestation info from SQL Server /// attestation parameters /// A set of extra data needed for attestating the enclave. From 500d0adb711f09591e97174e06491c80e791cb60 Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Tue, 7 Jul 2020 14:26:08 -0700 Subject: [PATCH 07/12] Update src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveDelegate.NetCoreApp.cs Updated parameter description Co-authored-by: Cheena Malhotra --- .../src/Microsoft/Data/SqlClient/EnclaveDelegate.NetCoreApp.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 440c2a309b..89d83cd691 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 @@ -105,7 +105,7 @@ internal void CreateEnclaveSession(SqlConnectionAttestationProtocol attestationP /// enclave type /// server name /// url for attestation endpoint - /// The database that SqlClient contacts to. + /// The database that SqlClient contacts to request an enclave session. /// internal EnclavePackage GenerateEnclavePackage(SqlConnectionAttestationProtocol attestationProtocol, Dictionary keysToBeSentToEnclave, string queryText, string enclaveType, string serverName, string enclaveAttestationUrl, string database) { From 8e1b95fdf289a34bd9c4582700bfd685dcf83f75 Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Tue, 7 Jul 2020 14:26:17 -0700 Subject: [PATCH 08/12] Update doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml Updated parameter description Co-authored-by: Cheena Malhotra --- .../SqlColumnEncryptionEnclaveProvider.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml index d00904b93f..edd47d550e 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml @@ -53,7 +53,7 @@ the enclave attestation protocol as well as the logic for creating and caching e The name of the SQL Server instance containing the enclave. The endpoint of an attestation service, SqlClient contacts to attest the enclave. - The database that SqlClient contacts to. + The database that SqlClient contacts to request an enclave session. The session to be invalidated. When overridden in a derived class, looks up and evicts an enclave session from the enclave session cache, if the provider implements session caching. To be added. From ea7a4a86cea95b6e6c1ebbc9b8e8e59f0b468d3e Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Tue, 7 Jul 2020 14:26:31 -0700 Subject: [PATCH 09/12] Update doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml Updated parameter description Co-authored-by: Cheena Malhotra --- .../SqlColumnEncryptionEnclaveProvider.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml index edd47d550e..008acca057 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml @@ -40,7 +40,7 @@ the enclave attestation protocol as well as the logic for creating and caching e The name of the SQL Server instance containing the enclave. The endpoint of an attestation service, SqlClient contacts to attest the enclave. - The database that SqlClient contacts to. + The database that SqlClient contacts to request an enclave session. to indicate that a set of extra data needs to be generated for attestation; otherwise, . When this method returns, the requested enclave session or if the provider doesn't implement session caching. This parameter is treated as uninitialized. 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. From fd2ab49f99178a68cb7ea67be75b2058b2cde48b Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Tue, 7 Jul 2020 18:08:18 -0700 Subject: [PATCH 10/12] Change based on eview comments --- .../EnclaveAzureDatabaseTests.cs | 57 ++++++++++--------- .../SQLSetupStrategyAzureKeyVault.cs | 2 +- .../ManualTests/DataCommon/DataTestUtility.cs | 5 +- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/EnclaveAzureDatabaseTests.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/EnclaveAzureDatabaseTests.cs index ef3f30551a..d90529976d 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/EnclaveAzureDatabaseTests.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/EnclaveAzureDatabaseTests.cs @@ -13,6 +13,7 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted { + // This test class is for internal use only public class EnclaveAzureDatabaseTests : IDisposable { private ColumnMasterKey akvColumnMasterKey; @@ -23,16 +24,21 @@ public class EnclaveAzureDatabaseTests : IDisposable public EnclaveAzureDatabaseTests() { - if (DataTestUtility.IsEnclaveAzureDatabaseSetup() && DataTestUtility.EnclaveEnabled) + if (DataTestUtility.IsEnclaveAzureDatabaseSetup()) { // Initialize AKV provider sqlColumnEncryptionAzureKeyVaultProvider = new SqlColumnEncryptionAzureKeyVaultProvider(AADUtility.AzureActiveDirectoryAuthenticationCallback); - // Register AKV provider - SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders: new Dictionary(capacity: 1, comparer: StringComparer.OrdinalIgnoreCase) - { - { SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, sqlColumnEncryptionAzureKeyVaultProvider} - }); + if (!SQLSetupStrategyAzureKeyVault.isAKVProviderRegistered) + { + // Register AKV provider + SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders: new Dictionary(capacity: 1, comparer: StringComparer.OrdinalIgnoreCase) + { + { SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, sqlColumnEncryptionAzureKeyVaultProvider} + }); + + SQLSetupStrategyAzureKeyVault.isAKVProviderRegistered = true; + } akvColumnMasterKey = new AkvColumnMasterKey(DatabaseHelper.GenerateUniqueName("AKVCMK"), akvUrl: DataTestUtility.AKVUrl, sqlColumnEncryptionAzureKeyVaultProvider, DataTestUtility.EnclaveEnabled); databaseObjects.Add(akvColumnMasterKey); @@ -66,28 +72,25 @@ public EnclaveAzureDatabaseTests() [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsEnclaveAzureDatabaseSetup))] public void ConnectToAzureDatabaseWithEnclave() { - if (DataTestUtility.EnclaveEnabled) - { - string tableName = DatabaseHelper.GenerateUniqueName("AzureTable"); + string tableName = DatabaseHelper.GenerateUniqueName("AzureTable"); - foreach (string connString in connStrings) + foreach (string connString in connStrings) + { + using (SqlConnection sqlConnection = new SqlConnection(connString)) { - using (SqlConnection sqlConnection = new SqlConnection(connString)) - { - sqlConnection.Open(); + sqlConnection.Open(); + + Customer customer = new Customer(1, @"Microsoft", @"Corporation"); - Customer customer = new Customer(1, @"Microsoft", @"Corporation"); - - try - { - CreateTable(sqlConnection, akvColumnEncryptionKey.Name, tableName); - InsertData(sqlConnection, tableName, customer); - VerifyData(sqlConnection, tableName, customer); - } - finally - { - DropTableIfExists(sqlConnection, tableName); - } + try + { + CreateTable(sqlConnection, akvColumnEncryptionKey.Name, tableName); + InsertData(sqlConnection, tableName, customer); + VerifyData(sqlConnection, tableName, customer); + } + finally + { + DropTableIfExists(sqlConnection, tableName); } } } @@ -165,7 +168,7 @@ private void DropTableIfExists(SqlConnection sqlConnection, string tableName) public void Dispose() { - if (DataTestUtility.IsEnclaveAzureDatabaseSetup() && DataTestUtility.EnclaveEnabled) + if (DataTestUtility.IsEnclaveAzureDatabaseSetup()) { databaseObjects.Reverse(); foreach (string connStr in connStrings) @@ -179,4 +182,4 @@ public void Dispose() } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategyAzureKeyVault.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategyAzureKeyVault.cs index b144673e82..3086235852 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategyAzureKeyVault.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategyAzureKeyVault.cs @@ -11,7 +11,7 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted { public class SQLSetupStrategyAzureKeyVault : SQLSetupStrategy { - private static bool isAKVProviderRegistered = false; + internal static bool isAKVProviderRegistered = false; public Table AKVTestTable { get; private set; } public SqlColumnEncryptionAzureKeyVaultProvider AkvStoreProvider; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 7cf7184618..60b506533e 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -289,7 +289,10 @@ public static bool IsSupportedDataClassification() public static bool IsDNSCachingSetup() => !string.IsNullOrEmpty(DNSCachingConnString); - public static bool IsEnclaveAzureDatabaseSetup() => !string.IsNullOrEmpty(EnclaveAzureDatabaseConnString); + public static bool IsEnclaveAzureDatabaseSetup() + { + return EnclaveEnabled && !string.IsNullOrEmpty(EnclaveAzureDatabaseConnString); + } public static bool IsUdtTestDatabasePresent() => IsDatabasePresent(UdtTestDbName); From df052247e7266c1fa31dc30f37632936bcf0063d Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Wed, 8 Jul 2020 13:04:20 -0700 Subject: [PATCH 11/12] Add delimiter in enclave session cache key --- .../Microsoft/Data/SqlClient/EnclaveSessionCache.NetCoreApp.cs | 2 +- .../netfx/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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.NetCoreApp.cs index ffcea85e07..fca492a60d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveSessionCache.NetCoreApp.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/EnclaveSessionCache.NetCoreApp.cs @@ -69,7 +69,7 @@ internal SqlEnclaveSession CreateSession(string attestationUrl, string serverNam // Generates the cache key for the enclave session cache private string GenerateCacheKey(string serverName, string attestationUrl, string database) { - return (serverName + database + attestationUrl).ToLowerInvariant(); + return (serverName + '+' + database + attestationUrl).ToLowerInvariant(); } } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs index d0906c6598..6e630dcaac 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs @@ -69,7 +69,7 @@ internal SqlEnclaveSession CreateSession(string attestationUrl, string serverNam // Generates the cache key for the enclave session cache private string GenerateCacheKey(string serverName, string attestationUrl, string database) { - return (serverName + database + attestationUrl).ToLowerInvariant(); + return (serverName + '+' + database + attestationUrl).ToLowerInvariant(); } } } From b296a050a18fc096ad7f5fa4c4c6cb404d474399 Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Wed, 15 Jul 2020 14:49:20 -0700 Subject: [PATCH 12/12] Update parameter description --- .../SqlColumnEncryptionEnclaveProvider.xml | 2 +- .../Microsoft/Data/SqlClient/EnclaveDelegate.NetCoreApp.cs | 2 +- .../Data/SqlClient/SimulatorEnclaveProvider.NetCoreApp.cs | 2 +- .../netfx/src/Microsoft/Data/SqlClient/EnclaveDelegate.cs | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml index 008acca057..304fc3d28b 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml @@ -21,7 +21,7 @@ the enclave attestation protocol as well as the logic for creating and caching e A Diffie-Hellman algorithm object that encapsulates a client-side key pair. The endpoint of an attestation service for attesting the enclave. The name of the SQL Server instance containing the enclave. - The database that SqlClient contacts to. + The database that SqlClient contacts to request an enclave session. The set of extra data needed for attestating the enclave. The length of the extra data needed for attestating the enclave. The requested enclave session or if the provider doesn't implement session caching. 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 89d83cd691..29c16dd021 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 @@ -64,7 +64,7 @@ internal byte[] GetSerializedAttestationParameters(SqlEnclaveAttestationParamete /// enclave type /// servername /// attestation url for attestation service endpoint - /// The database that SqlClient contacts to. + /// The database that SqlClient contacts to request an enclave session. /// attestation info from SQL Server /// attestation parameters /// A set of extra data needed for attestating the enclave. 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 2f939e16c7..ffb066dfb3 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 @@ -107,7 +107,7 @@ public override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellma /// /// The name of the SQL Server instance containing the enclave. /// The endpoint of an attestation service, SqlClient contacts to attest the enclave. - /// The database that SqlClient contacts to. + /// The database that SqlClient contacts to request an enclave session. /// The session to be invalidated. public override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, string database, SqlEnclaveSession enclaveSessionToInvalidate) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveDelegate.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveDelegate.cs index 8fc1b9d493..9a58c8978a 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveDelegate.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/EnclaveDelegate.cs @@ -42,7 +42,7 @@ private EnclaveDelegate() { } /// enclave type /// server name /// url for attestation endpoint - /// The database that SqlClient contacts to. + /// The database that SqlClient contacts to request an enclave session. /// internal EnclavePackage GenerateEnclavePackage(SqlConnectionAttestationProtocol attestationProtocol, Dictionary keysTobeSentToEnclave, string queryText, string enclaveType, string serverName, string enclaveAttestationUrl, string database) { @@ -160,7 +160,7 @@ private byte[] GetUintBytes(string enclaveType, int intValue, string variableNam /// enclave type /// servername /// attestation url for attestation service endpoint - /// The database that SqlClient contacts to. + /// The database that SqlClient contacts to request an enclave session. /// attestation info from SQL Server /// attestation parameters /// A set of extra data needed for attestating the enclave.