diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionAttestationProtocol.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionAttestationProtocol.xml index 3f64ef38b8..d5f32ef2d3 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionAttestationProtocol.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionAttestationProtocol.xml @@ -13,6 +13,10 @@ Attestation portocol for Azure Attestation Service 1 + + Attestation protocol for Simulator + 2 + Attestation protocol for Host Guardian Service 3 diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 99dc4bc27a..955ea8cc4a 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -39,6 +39,10 @@ $(DotNetRoot)dotnet $(DotNetCmd).exe true + false + + + $(DefineConstants);ENCLAVE_SIMULATOR diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.NetCoreApp.cs index 965902f3b8..837533659c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.NetCoreApp.cs +++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.NetCoreApp.cs @@ -113,6 +113,11 @@ public enum SqlConnectionAttestationProtocol /// AAS = 1, +#if ENCLAVE_SIMULATOR + /// + SIM = 2, +#endif + /// HGS = 3 } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 7b20a62142..1b8b1bb014 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -53,6 +53,9 @@ + + + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionStringCommon.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionStringCommon.cs index c45b12af7f..8cf67f1aca 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionStringCommon.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionStringCommon.cs @@ -221,6 +221,9 @@ internal static string ColumnEncryptionSettingToString(SqlConnectionColumnEncryp /// const string AttestationProtocolHGS = "HGS"; const string AttestationProtocolAAS = "AAS"; +#if ENCLAVE_SIMULATOR + const string AttestationProtocolSIM = "SIM"; +#endif /// /// Convert a string value to the corresponding SqlConnectionAttestationProtocol @@ -240,6 +243,13 @@ internal static bool TryConvertToAttestationProtocol(string value, out SqlConnec result = SqlConnectionAttestationProtocol.AAS; return true; } +#if ENCLAVE_SIMULATOR + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, AttestationProtocolSIM)) + { + result = SqlConnectionAttestationProtocol.SIM; + return true; + } +#endif else { result = DbConnectionStringDefaults.AttestationProtocol; @@ -249,11 +259,18 @@ internal static bool TryConvertToAttestationProtocol(string value, out SqlConnec internal static bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol value) { +#if ENCLAVE_SIMULATOR + Debug.Assert(Enum.GetNames(typeof(SqlConnectionAttestationProtocol)).Length == 4, "SqlConnectionAttestationProtocol enum has changed, update needed"); + return value == SqlConnectionAttestationProtocol.NotSpecified + || value == SqlConnectionAttestationProtocol.HGS + || value == SqlConnectionAttestationProtocol.AAS + || value == SqlConnectionAttestationProtocol.SIM; +#else Debug.Assert(Enum.GetNames(typeof(SqlConnectionAttestationProtocol)).Length == 3, "SqlConnectionAttestationProtocol enum has changed, update needed"); return value == SqlConnectionAttestationProtocol.NotSpecified || value == SqlConnectionAttestationProtocol.HGS || value == SqlConnectionAttestationProtocol.AAS; - +#endif } internal static string AttestationProtocolToString(SqlConnectionAttestationProtocol value) @@ -266,6 +283,10 @@ internal static string AttestationProtocolToString(SqlConnectionAttestationProto return AttestationProtocolHGS; case SqlConnectionAttestationProtocol.AAS: return AttestationProtocolAAS; +#if ENCLAVE_SIMULATOR + case SqlConnectionAttestationProtocol.SIM: + return AttestationProtocolSIM; +#endif default: return null; } 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 48473b0722..a9ff36f11d 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 @@ -166,6 +166,14 @@ private SqlColumnEncryptionEnclaveProvider GetEnclaveProvider(SqlConnectionAttes sqlColumnEncryptionEnclaveProvider = EnclaveProviders[attestationProtocol]; break; +#if ENCLAVE_SIMULATOR + case SqlConnectionAttestationProtocol.SIM: + SimulatorEnclaveProvider simulatorEnclaveProvider = new SimulatorEnclaveProvider(); + EnclaveProviders[attestationProtocol] = (SqlColumnEncryptionEnclaveProvider)simulatorEnclaveProvider; + sqlColumnEncryptionEnclaveProvider = EnclaveProviders[attestationProtocol]; + break; +#endif + default: break; } @@ -189,6 +197,11 @@ private string ConvertAttestationProtocolToString(SqlConnectionAttestationProtoc case SqlConnectionAttestationProtocol.HGS: return "HGS"; +#if ENCLAVE_SIMULATOR + case SqlConnectionAttestationProtocol.SIM: + return "SIM"; +#endif + default: return "NotSpecified"; } 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 new file mode 100644 index 0000000000..542af35688 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.NetCoreApp.cs @@ -0,0 +1,116 @@ +// 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.Collections.Generic; +using System.Data.SqlClient; +using System.Diagnostics; +using System.Linq; +using System.Runtime.Caching; +using System.Security.Cryptography; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Concurrent; + +namespace Microsoft.Data.SqlClient +{ + internal class SimulatorEnclaveProvider : EnclaveProviderBase + { + private static readonly int EnclaveSessionHandleSize = 8; + + // 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) + { + GetEnclaveSessionHelper(servername, attestationUrl, 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. + // The information SqlClient subsequently uses to initiate the process of attesting the enclave and to establish a secure session with the enclave. + public override SqlEnclaveAttestationParameters GetAttestationParameters(string attestationUrl, byte[] customData, int customDataLength) + { + ECDiffieHellmanCng clientDHKey = new ECDiffieHellmanCng(384); + clientDHKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; + clientDHKey.HashAlgorithm = CngAlgorithm.Sha256; + + return new SqlEnclaveAttestationParameters(2, new byte[] { }, clientDHKey); + } + + // When overridden in a derived class, performs enclave attestation, generates a symmetric key for the session, creates a an enclave session and stores the session information in the cache. + public override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellmanCng clientDHKey, string attestationUrl, string servername, 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) + + sqlEnclaveSession = null; + counter = 0; + try + { + ThreadRetryCache.Remove(Thread.CurrentThread.ManagedThreadId.ToString()); + sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, out counter); + + if (sqlEnclaveSession == null) + { + if (!string.IsNullOrEmpty(attestationUrl)) + { + ////Read AttestationInfo + int attestationInfoOffset = 0; + uint sizeOfTrustedModuleAttestationInfoBuffer = BitConverter.ToUInt32(attestationInfo, attestationInfoOffset); + attestationInfoOffset += sizeof(UInt32); + int sizeOfTrustedModuleAttestationInfoBufferInt = checked((int)sizeOfTrustedModuleAttestationInfoBuffer); + Debug.Assert(sizeOfTrustedModuleAttestationInfoBuffer == 0); + + ////read secure session info + uint sizeOfSecureSessionInfoResponse = BitConverter.ToUInt32(attestationInfo, attestationInfoOffset); + attestationInfoOffset += sizeof(UInt32); + + byte[] enclaveSessionHandle = new byte[EnclaveSessionHandleSize]; + Buffer.BlockCopy(attestationInfo, attestationInfoOffset, enclaveSessionHandle, 0, EnclaveSessionHandleSize); + attestationInfoOffset += EnclaveSessionHandleSize; + + uint sizeOfTrustedModuleDHPublicKeyBuffer = BitConverter.ToUInt32(attestationInfo, attestationInfoOffset); + attestationInfoOffset += sizeof(UInt32); + uint sizeOfTrustedModuleDHPublicKeySignatureBuffer = BitConverter.ToUInt32(attestationInfo, attestationInfoOffset); + attestationInfoOffset += sizeof(UInt32); + int sizeOfTrustedModuleDHPublicKeyBufferInt = checked((int)sizeOfTrustedModuleDHPublicKeyBuffer); + + byte[] trustedModuleDHPublicKey = new byte[sizeOfTrustedModuleDHPublicKeyBuffer]; + Buffer.BlockCopy(attestationInfo, attestationInfoOffset, trustedModuleDHPublicKey, 0, + sizeOfTrustedModuleDHPublicKeyBufferInt); + attestationInfoOffset += sizeOfTrustedModuleDHPublicKeyBufferInt; + + byte[] trustedModuleDHPublicKeySignature = new byte[sizeOfTrustedModuleDHPublicKeySignatureBuffer]; + Buffer.BlockCopy(attestationInfo, attestationInfoOffset, trustedModuleDHPublicKeySignature, 0, + checked((int)sizeOfTrustedModuleDHPublicKeySignatureBuffer)); + + 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); + } + else + { + throw new AlwaysEncryptedAttestationException(SR.FailToCreateEnclaveSession); + } + } + } + finally + { + UpdateEnclaveSessionLockStatus(sqlEnclaveSession); + } + } + + /// + /// When overridden in a derived class, looks up and evicts an enclave session from the enclave session cache, if the provider implements session caching. + /// + /// The name of the SQL Server instance containing the enclave. + /// The endpoint of an attestation service, SqlClient contacts to attest the enclave. + /// The session to be invalidated. + public override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSessionToInvalidate) + { + InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, enclaveSessionToInvalidate); + } + } +} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsEnums.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsEnums.cs index 48aadf85e5..8828409ddf 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsEnums.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsEnums.cs @@ -983,6 +983,9 @@ internal static string GetSniContextEnumName(SniContext sniContext) internal const int AEAD_AES_256_CBC_HMAC_SHA256 = 2; internal const string ENCLAVE_TYPE_VBS = "VBS"; internal const string ENCLAVE_TYPE_SGX = "SGX"; +#if ENCLAVE_SIMULATOR + internal const string ENCLAVE_TYPE_SIMULATOR = "SIMULATOR"; +#endif // TCE Param names for exec handling internal const string TCE_PARAM_CIPHERTEXT = "cipherText"; @@ -1056,6 +1059,11 @@ public enum SqlConnectionAttestationProtocol /// AAS = 1, +#if ENCLAVE_SIMULATOR + /// + SIM = 2, +#endif + /// HGS = 3 } @@ -1159,4 +1167,3 @@ internal enum DescribeParameterEncryptionResultSet3 AttestationInfo = 0, } } - diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index ccb91ccef5..2deeb33ede 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -3017,10 +3017,13 @@ private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) private bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType) { - switch (enclaveType) + switch (enclaveType.ToUpper()) { case TdsEnums.ENCLAVE_TYPE_VBS: if (attestationProtocol != SqlConnectionAttestationProtocol.AAS +#if ENCLAVE_SIMULATOR + && attestationProtocol != SqlConnectionAttestationProtocol.SIM +#endif && attestationProtocol != SqlConnectionAttestationProtocol.HGS) { return false; @@ -3028,12 +3031,25 @@ private bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol attesta break; case TdsEnums.ENCLAVE_TYPE_SGX: +#if ENCLAVE_SIMULATOR + if (attestationProtocol != SqlConnectionAttestationProtocol.AAS + && attestationProtocol != SqlConnectionAttestationProtocol.SIM) +#else if (attestationProtocol != SqlConnectionAttestationProtocol.AAS) +#endif { return false; } break; +#if ENCLAVE_SIMULATOR + case TdsEnums.ENCLAVE_TYPE_SIMULATOR: + if (attestationProtocol != SqlConnectionAttestationProtocol.SIM) + { + return false; + } + break; +#endif default: // if we reach here, the enclave type is not supported throw SQL.EnclaveTypeNotSupported(enclaveType); @@ -3052,6 +3068,11 @@ private string ConvertAttestationProtocolToString(SqlConnectionAttestationProtoc case SqlConnectionAttestationProtocol.HGS: return "HGS"; +#if ENCLAVE_SIMULATOR + case SqlConnectionAttestationProtocol.SIM: + return "SIM"; +#endif + default: return "NotSpecified"; } diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs index 8a9fa8429d..6371d4fbca 100644 --- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs +++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs @@ -801,6 +801,11 @@ public enum SqlConnectionAttestationProtocol /// AAS = 1, +#if ENCLAVE_SIMULATOR + /// + SIM = 2, +#endif + /// HGS = 3 } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 273812e690..99fe9cb877 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -309,6 +309,9 @@ + + + diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs index 772f422b1a..08857968cb 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs @@ -822,6 +822,9 @@ internal static SqlConnectionColumnEncryptionSetting ConvertToColumnEncryptionSe /// const string AttestationProtocolHGS = "HGS"; const string AttestationProtocolAAS = "AAS"; +#if ENCLAVE_SIMULATOR + const string AttestationProtocolSIM = "SIM"; +#endif /// /// Convert a string value to the corresponding SqlConnectionAttestationProtocol @@ -841,6 +844,13 @@ internal static bool TryConvertToAttestationProtocol(string value, out SqlConnec result = SqlConnectionAttestationProtocol.AAS; return true; } +#if ENCLAVE_SIMULATOR + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, AttestationProtocolSIM)) + { + result = SqlConnectionAttestationProtocol.SIM; + return true; + } +#endif else { result = DbConnectionStringDefaults.AttestationProtocol; @@ -850,11 +860,18 @@ internal static bool TryConvertToAttestationProtocol(string value, out SqlConnec internal static bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol value) { +#if ENCLAVE_SIMULATOR + Debug.Assert(Enum.GetNames(typeof(SqlConnectionAttestationProtocol)).Length == 4, "SqlConnectionAttestationProtocol enum has changed, update needed"); + return value == SqlConnectionAttestationProtocol.NotSpecified + || value == SqlConnectionAttestationProtocol.HGS + || value == SqlConnectionAttestationProtocol.AAS + || value == SqlConnectionAttestationProtocol.SIM; +#else Debug.Assert(Enum.GetNames(typeof(SqlConnectionAttestationProtocol)).Length == 3, "SqlConnectionAttestationProtocol enum has changed, update needed"); return value == SqlConnectionAttestationProtocol.NotSpecified || value == SqlConnectionAttestationProtocol.HGS || value == SqlConnectionAttestationProtocol.AAS; - +#endif } internal static string AttestationProtocolToString(SqlConnectionAttestationProtocol value) @@ -867,6 +884,10 @@ internal static string AttestationProtocolToString(SqlConnectionAttestationProto return AttestationProtocolHGS; case SqlConnectionAttestationProtocol.AAS: return AttestationProtocolAAS; +#if ENCLAVE_SIMULATOR + case SqlConnectionAttestationProtocol.SIM: + return AttestationProtocolSIM; +#endif default: return null; } 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 3ab2a78a38..d57bc47067 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 @@ -212,6 +212,14 @@ private SqlColumnEncryptionEnclaveProvider GetEnclaveProvider(SqlConnectionAttes sqlColumnEncryptionEnclaveProvider = EnclaveProviders[attestationProtocol]; break; +#if ENCLAVE_SIMULATOR + case SqlConnectionAttestationProtocol.SIM: + SimulatorEnclaveProvider simulatorEnclaveProvider = new SimulatorEnclaveProvider(); + EnclaveProviders[attestationProtocol] = (SqlColumnEncryptionEnclaveProvider)simulatorEnclaveProvider; + sqlColumnEncryptionEnclaveProvider = EnclaveProviders[attestationProtocol]; + break; +#endif + default: break; } @@ -235,6 +243,11 @@ private string ConvertAttestationProtocolToString(SqlConnectionAttestationProtoc case SqlConnectionAttestationProtocol.HGS: return "HGS"; +#if ENCLAVE_SIMULATOR + case SqlConnectionAttestationProtocol.SIM: + return "SIM"; +#endif + default: return "NotSpecified"; } 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 new file mode 100644 index 0000000000..811816f1e6 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs @@ -0,0 +1,116 @@ +// 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.Collections.Generic; +using System.Data.SqlClient; +using System.Diagnostics; +using System.Linq; +using System.Runtime.Caching; +using System.Security.Cryptography; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Concurrent; + +namespace Microsoft.Data.SqlClient +{ + internal class SimulatorEnclaveProvider : EnclaveProviderBase + { + private static readonly int EnclaveSessionHandleSize = 8; + + // 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) + { + GetEnclaveSessionHelper(servername, attestationUrl, 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. + // The information SqlClient subsequently uses to initiate the process of attesting the enclave and to establish a secure session with the enclave. + public override SqlEnclaveAttestationParameters GetAttestationParameters(string attestationUrl, byte[] customData, int customDataLength) + { + ECDiffieHellmanCng clientDHKey = new ECDiffieHellmanCng(384); + clientDHKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; + clientDHKey.HashAlgorithm = CngAlgorithm.Sha256; + + return new SqlEnclaveAttestationParameters(2, new byte[] { }, clientDHKey); + } + + // When overridden in a derived class, performs enclave attestation, generates a symmetric key for the session, creates a an enclave session and stores the session information in the cache. + public override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellmanCng clientDHKey, string attestationUrl, string servername, 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) + + sqlEnclaveSession = null; + counter = 0; + try + { + ThreadRetryCache.Remove(Thread.CurrentThread.ManagedThreadId.ToString()); + sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, out counter); + + if (sqlEnclaveSession == null) + { + if (!string.IsNullOrEmpty(attestationUrl)) + { + ////Read AttestationInfo + int attestationInfoOffset = 0; + uint sizeOfTrustedModuleAttestationInfoBuffer = BitConverter.ToUInt32(attestationInfo, attestationInfoOffset); + attestationInfoOffset += sizeof(UInt32); + int sizeOfTrustedModuleAttestationInfoBufferInt = checked((int)sizeOfTrustedModuleAttestationInfoBuffer); + Debug.Assert(sizeOfTrustedModuleAttestationInfoBuffer == 0); + + ////read secure session info + uint sizeOfSecureSessionInfoResponse = BitConverter.ToUInt32(attestationInfo, attestationInfoOffset); + attestationInfoOffset += sizeof(UInt32); + + byte[] enclaveSessionHandle = new byte[EnclaveSessionHandleSize]; + Buffer.BlockCopy(attestationInfo, attestationInfoOffset, enclaveSessionHandle, 0, EnclaveSessionHandleSize); + attestationInfoOffset += EnclaveSessionHandleSize; + + uint sizeOfTrustedModuleDHPublicKeyBuffer = BitConverter.ToUInt32(attestationInfo, attestationInfoOffset); + attestationInfoOffset += sizeof(UInt32); + uint sizeOfTrustedModuleDHPublicKeySignatureBuffer = BitConverter.ToUInt32(attestationInfo, attestationInfoOffset); + attestationInfoOffset += sizeof(UInt32); + int sizeOfTrustedModuleDHPublicKeyBufferInt = checked((int)sizeOfTrustedModuleDHPublicKeyBuffer); + + byte[] trustedModuleDHPublicKey = new byte[sizeOfTrustedModuleDHPublicKeyBuffer]; + Buffer.BlockCopy(attestationInfo, attestationInfoOffset, trustedModuleDHPublicKey, 0, + sizeOfTrustedModuleDHPublicKeyBufferInt); + attestationInfoOffset += sizeOfTrustedModuleDHPublicKeyBufferInt; + + byte[] trustedModuleDHPublicKeySignature = new byte[sizeOfTrustedModuleDHPublicKeySignatureBuffer]; + Buffer.BlockCopy(attestationInfo, attestationInfoOffset, trustedModuleDHPublicKeySignature, 0, + checked((int)sizeOfTrustedModuleDHPublicKeySignatureBuffer)); + + 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); + } + else + { + throw new AlwaysEncryptedAttestationException(Strings.FailToCreateEnclaveSession); + } + } + } + finally + { + UpdateEnclaveSessionLockStatus(sqlEnclaveSession); + } + } + + /// + /// When overridden in a derived class, looks up and evicts an enclave session from the enclave session cache, if the provider implements session caching. + /// + /// The name of the SQL Server instance containing the enclave. + /// The endpoint of an attestation service, SqlClient contacts to attest the enclave. + /// The session to be invalidated. + public override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSessionToInvalidate) + { + InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, enclaveSessionToInvalidate); + } + } +} diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsEnums.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsEnums.cs index 8661bc70e7..f09836b163 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsEnums.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsEnums.cs @@ -947,7 +947,9 @@ internal enum FedAuthInfoId : byte internal const int AEAD_AES_256_CBC_HMAC_SHA256 = 2; internal const string ENCLAVE_TYPE_VBS = "VBS"; internal const string ENCLAVE_TYPE_SGX = "SGX"; - +#if ENCLAVE_SIMULATOR + internal const string ENCLAVE_TYPE_SIMULATOR = "SIMULATOR"; +#endif // TCE Param names for exec handling internal const string TCE_PARAM_CIPHERTEXT = "cipherText"; internal const string TCE_PARAM_CIPHER_ALGORITHM_ID = "cipherAlgorithmId"; @@ -1046,6 +1048,11 @@ public enum SqlConnectionAttestationProtocol /// AAS = 1, +#if ENCLAVE_SIMULATOR + /// + SIM = 2, +#endif + /// HGS = 3 } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 1c906042f1..33bec28e89 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -3485,10 +3485,13 @@ private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) private bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType) { - switch (enclaveType) + switch (enclaveType.ToUpper()) { case TdsEnums.ENCLAVE_TYPE_VBS: if (attestationProtocol != SqlConnectionAttestationProtocol.AAS +#if ENCLAVE_SIMULATOR + && attestationProtocol != SqlConnectionAttestationProtocol.SIM +#endif && attestationProtocol != SqlConnectionAttestationProtocol.HGS) { return false; @@ -3496,12 +3499,25 @@ private bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol attesta break; case TdsEnums.ENCLAVE_TYPE_SGX: +#if ENCLAVE_SIMULATOR + if (attestationProtocol != SqlConnectionAttestationProtocol.AAS + && attestationProtocol != SqlConnectionAttestationProtocol.SIM) +#else if (attestationProtocol != SqlConnectionAttestationProtocol.AAS) +#endif { return false; } break; +#if ENCLAVE_SIMULATOR + case TdsEnums.ENCLAVE_TYPE_SIMULATOR: + if (attestationProtocol != SqlConnectionAttestationProtocol.SIM) + { + return false; + } + break; +#endif default: // if we reach here, the enclave type is not supported throw SQL.EnclaveTypeNotSupported(enclaveType); @@ -3520,6 +3536,11 @@ private string ConvertAttestationProtocolToString(SqlConnectionAttestationProtoc case SqlConnectionAttestationProtocol.HGS: return "HGS"; +#if ENCLAVE_SIMULATOR + case SqlConnectionAttestationProtocol.SIM: + return "SIM"; +#endif + default: return "NotSpecified"; }