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";
}