Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
<summary>Attestation portocol for Azure Attestation Service</summary>
<value>1</value>
</AAS>
<SIM>
<summary>Attestation protocol for Simulator</summary>
<value>2</value>
</SIM>
<HGS>
<summary>Attestation protocol for Host Guardian Service</summary>
<value>3</value>
Expand Down
4 changes: 4 additions & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
<DotNetCmd>$(DotNetRoot)dotnet</DotNetCmd>
<DotNetCmd Condition="'$(OS)' == 'Windows_NT'">$(DotNetCmd).exe</DotNetCmd>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<BuildSimulator Condition="'$(BuildSimulator)' != 'true'">false</BuildSimulator>
</PropertyGroup>
<PropertyGroup Condition="'$(BuildSimulator)' == 'true'">
<DefineConstants>$(DefineConstants);ENCLAVE_SIMULATOR</DefineConstants>
</PropertyGroup>

<!-- Provides Version properties -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ public enum SqlConnectionAttestationProtocol
/// <include file='..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionAttestationProtocol.xml' path='docs/members[@name="SqlConnectionAttestationProtocol"]/AAS/*' />
AAS = 1,

#if ENCLAVE_SIMULATOR
/// <include file='..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionAttestationProtocol.xml' path='docs/members[@name="SqlConnectionAttestationProtocol"]/SIM/*' />
SIM = 2,
Comment thread
cheenamalhotra marked this conversation as resolved.
#endif

/// <include file='..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionAttestationProtocol.xml' path='docs/members[@name="SqlConnectionAttestationProtocol"]/HGS/*' />
HGS = 3
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
<Compile Include="Microsoft\Data\SqlClient\EnclaveProviderBase.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\EnclaveSessionCache.NetCoreApp.cs" />
</ItemGroup>
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netcoreapp' AND '$(BuildSimulator)' == 'true'">
<Compile Include="Microsoft\Data\SqlClient\SimulatorEnclaveProvider.NetCoreApp.cs" />
</ItemGroup>
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netstandard'">
<Compile Include="Microsoft\Data\SqlClient\SqlDelegatedTransaction.NetStandard.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsParser.NetStandard.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ internal static string ColumnEncryptionSettingToString(SqlConnectionColumnEncryp
/// </summary>
const string AttestationProtocolHGS = "HGS";
const string AttestationProtocolAAS = "AAS";
#if ENCLAVE_SIMULATOR
const string AttestationProtocolSIM = "SIM";
#endif

/// <summary>
/// Convert a string value to the corresponding SqlConnectionAttestationProtocol
Expand All @@ -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;
Expand All @@ -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)
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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";
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
// <returns>The information SqlClient subsequently uses to initiate the process of attesting the enclave and to establish a secure session with the enclave.</returns>
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);
}
}

/// <summary>
/// When overridden in a derived class, looks up and evicts an enclave session from the enclave session cache, if the provider implements session caching.
/// </summary>
/// <param name="serverName">The name of the SQL Server instance containing the enclave.</param>
/// <param name="enclaveAttestationUrl">The endpoint of an attestation service, SqlClient contacts to attest the enclave.</param>
/// <param name="enclaveSessionToInvalidate">The session to be invalidated.</param>
public override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSessionToInvalidate)
{
InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, enclaveSessionToInvalidate);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -1056,6 +1059,11 @@ public enum SqlConnectionAttestationProtocol
/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionAttestationProtocol.xml' path='docs/members[@name="SqlConnectionAttestationProtocol"]/AAS/*' />
AAS = 1,

#if ENCLAVE_SIMULATOR
/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionAttestationProtocol.xml' path='docs/members[@name="SqlConnectionAttestationProtocol"]/SIM/*' />
SIM = 2,
#endif

/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionAttestationProtocol.xml' path='docs/members[@name="SqlConnectionAttestationProtocol"]/HGS/*' />
HGS = 3
}
Expand Down Expand Up @@ -1159,4 +1167,3 @@ internal enum DescribeParameterEncryptionResultSet3
AttestationInfo = 0,
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -3017,23 +3017,39 @@ 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;
}
break;

case TdsEnums.ENCLAVE_TYPE_SGX:
#if ENCLAVE_SIMULATOR
if (attestationProtocol != SqlConnectionAttestationProtocol.AAS
&& attestationProtocol != SqlConnectionAttestationProtocol.SIM)
Comment thread
cheenamalhotra marked this conversation as resolved.
#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);
Expand All @@ -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";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,11 @@ public enum SqlConnectionAttestationProtocol
/// <include file='..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionAttestationProtocol.xml' path='docs/members[@name="SqlConnectionAttestationProtocol"]/AAS/*' />
AAS = 1,

#if ENCLAVE_SIMULATOR
/// <include file='..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionAttestationProtocol.xml' path='docs/members[@name="SqlConnectionAttestationProtocol"]/SIM/*' />
SIM = 2,
#endif

/// <include file='..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionAttestationProtocol.xml' path='docs/members[@name="SqlConnectionAttestationProtocol"]/HGS/*' />
HGS = 3
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,9 @@
<Compile Include="Microsoft\Data\ProviderBase\FieldNameLookup.cs" />
<Compile Include="Microsoft\Data\OperationAbortedException.cs" />
</ItemGroup>
<ItemGroup Condition="'$(BuildSimulator)' == 'true'">
<Compile Include="Microsoft\Data\SqlClient\SimulatorEnclaveProvider.cs" />
</ItemGroup>
<!-- Resources -->
<ItemGroup>
<Compile Include="Resources\$(ResxFileName).Designer.cs">
Expand Down
Loading