Skip to content

Commit 146ecd9

Browse files
authored
Feature | AE with enclaves - multi-platform and .NET Standard 2.1 support (#676)
1 parent e10b230 commit 146ecd9

36 files changed

+371
-221
lines changed

build.proj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<NetCoreDriver Include="**/netcore/**/Microsoft.Data.SqlClient*.csproj" />
2626
<AKVProvider Include="**/add-ons/**/AzureKeyVaultProvider/*.csproj" />
2727

28-
<FunctionalTests Include="**/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj" />
28+
<FunctionalTests Condition="$(ReferenceType.Contains('NetStandard'))" Include="**/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj" />
2929
<FunctionalTests Include="**/tools/TDS/TDS/TDS.csproj" />
3030
<FunctionalTests Include="**/tools/TDS/TDS.EndPoint/TDS.EndPoint.csproj" />
3131
<FunctionalTests Include="**/tools/TDS/TDS.Servers/TDS.Servers.csproj" />
@@ -34,7 +34,7 @@
3434
<FunctionalTests Include="**/ManualTests/SQL/UdtTest/UDTs/Address/Address.csproj" />
3535
<FunctionalTests Include="**/Microsoft.Data.SqlClient.Tests.csproj" />
3636

37-
<ManualTests Include="**/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj" />
37+
<ManualTests Condition="$(ReferenceType.Contains('NetStandard'))" Include="**/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj" />
3838
<ManualTests Include="**/ManualTests/SQL/UdtTest/UDTs/Address/Address.csproj" />
3939
<ManualTests Include="**/ManualTests/SQL/UdtTest/UDTs/Circle/Circle.csproj" />
4040
<ManualTests Include="**/ManualTests/SQL/UdtTest/UDTs/Shapes/Shapes.csproj" />
@@ -116,14 +116,14 @@
116116
<MSBuild Projects="@(AKVProvider)" Properties="TestTargetOS=$(TestOS)netfx;Platform=$(Platform);$(TestProjectProperties)" />
117117
</Target>
118118

119-
<Target Name="BuildAKVNetCore" Condition="!$(ReferenceType.Contains('NetStandard'))">
119+
<Target Name="BuildAKVNetCore">
120120
<MSBuild Projects="@(AKVProvider)" Targets="restore" Properties="TestTargetOS=$(TestOS)netcoreapp" />
121121
<!-- Only build platform specific builds for Package reference types -->
122122
<MSBuild Projects="@(AKVProvider)" Properties="TestTargetOS=$(TestOS)netcoreapp;$(ProjectProperties);Platform=AnyCPU;" Condition="!$(ReferenceType.Contains('Package'))"/>
123123
<MSBuild Projects="@(AKVProvider)" Properties="TestTargetOS=$(TestOS)netcoreapp;$(ProjectProperties);Platform=$(Platform);" Condition="$(ReferenceType.Contains('Package'))"/>
124124
</Target>
125125

126-
<Target Name="BuildAKVNetCoreAllOS" Condition="!$(ReferenceType.Contains('NetStandard'))">
126+
<Target Name="BuildAKVNetCoreAllOS">
127127
<MSBuild Projects="@(AKVProvider)" Targets="restore" Properties="TestTargetOS=$(TestOS)netcoreapp" />
128128
<MSBuild Projects="@(AKVProvider)" Properties="TestTargetOS=$(TestOS)netcoreapp;$(ProjectProperties);Platform=AnyCPU;OSGroup=Unix;" RemoveProperties="TargetsWindows;TargetsUnix;" />
129129
<MSBuild Projects="@(AKVProvider)" Properties="TestTargetOS=$(TestOS)netcoreapp;$(ProjectProperties);Platform=AnyCPU;OSGroup=Windows_NT;" RemoveProperties="TargetsWindows;TargetsUnix;" Condition="'$(IsEnabledWindows)' == 'true'" />

src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<ProjectGuid>{9073ABEF-92E0-4702-BB23-2C99CEF9BDD7}</ProjectGuid>
77
<TargetGroup Condition="$(TargetFramework.StartsWith('netcoreapp'))">netcoreapp</TargetGroup>
88
<TargetGroup Condition="$(TargetFramework.StartsWith('net4'))">netfx</TargetGroup>
9-
<Configurations>Debug;Release;net46-Release;net46-Debug;netcoreapp2.1-Debug;netcoreapp2.1-Release;</Configurations>
9+
<Configurations>Debug;Release;net46-Release;net46-Debug;netcoreapp2.1-Debug;netcoreapp2.1-Release;netcoreapp3.1-Debug;netcoreapp3.1-Release</Configurations>
1010
<Platforms>AnyCPU;x86;x64</Platforms>
1111
<IntermediateOutputPath>$(ObjFolder)$(Configuration).$(Platform)\$(AddOnName)</IntermediateOutputPath>
1212
<OutputPath>$(BinFolder)$(Configuration).$(Platform)\$(AddOnName)</OutputPath>

src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
<When Condition="'$(TestTargetOS)' != ''">
2020
<PropertyGroup>
2121
<TargetFramework Condition="'$(TestTargetOS)' == 'Windowsnetcoreapp' OR '$(TestTargetOS)' == 'Unixnetcoreapp'">netcoreapp2.1</TargetFramework>
22+
<TargetFramework Condition="('$(TestTargetOS)' == 'Windowsnetcoreapp' OR '$(TestTargetOS)' == 'Unixnetcoreapp') AND ($(ReferenceType)=='NetStandard' AND $(TargetNetStandardVersion)=='netstandard2.1')">netcoreapp3.1</TargetFramework>
2223
<TargetFramework Condition="'$(TestTargetOS)' == 'Windowsnetfx'">net46</TargetFramework>
2324
</PropertyGroup>
2425
</When>

src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
4-
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;netstandard2.0</TargetFrameworks>
4+
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;netstandard2.0;netstandard2.1</TargetFrameworks>
5+
<TargetFrameworks Condition="$(ReferenceType)=='NetStandard' AND $(TargetNetStandardVersion)=='netstandard2.1'">netstandard2.1</TargetFrameworks>
56
<IntermediateOutputPath>$(ObjFolder)$(Configuration)\$(AssemblyName)\ref\</IntermediateOutputPath>
67
<OutputPath>$(BinFolder)$(Configuration)\$(AssemblyName)\ref\</OutputPath>
78
<DocumentationFile>$(OutputPath)\$(TargetFramework)\Microsoft.Data.SqlClient.xml</DocumentationFile>

src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<AssemblyName>Microsoft.Data.SqlClient</AssemblyName>
4-
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;netstandard2.0</TargetFrameworks>
4+
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;netstandard2.0;netstandard2.1</TargetFrameworks>
5+
<TargetFrameworks Condition="$(ReferenceType)=='NetStandard' AND $(TargetNetStandardVersion)=='netstandard2.1'">netstandard2.1</TargetFrameworks>
56
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(OSGroup)' == 'AnyOS'">Strings.PlatformNotSupported_DataSqlClient</GeneratePlatformNotSupportedAssemblyMessage>
67
<OSGroup Condition="'$(OSGroup)' == ''">$(OS)</OSGroup>
78
<TargetsWindows Condition="'$(OSGroup)'=='Windows_NT'">true</TargetsWindows>
@@ -226,38 +227,40 @@
226227
<ItemGroup Condition="'$(TargetGroup)' == 'netstandard' OR '$(TargetGroup)' == 'netcoreapp' OR '$(IsUAPAssembly)' == 'true'">
227228
<Compile Include="Microsoft.Data.SqlClient.TypeForwards.cs" />
228229
</ItemGroup>
229-
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netstandard'">
230-
<Compile Include="Microsoft\Data\SqlClient\SqlAuthenticationProviderManager.NetStandard.cs" />
231-
<Compile Include="Microsoft\Data\SqlClient\SqlDiagnosticListener.NetStandard.cs" />
230+
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netstandard' AND '$(TargetFramework)' == 'netstandard2.0'">
232231
<Compile Include="Microsoft\Data\SqlClient\EnclaveDelegate.NetStandard.cs" />
233232
</ItemGroup>
233+
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netstandard'">
234+
<Compile Include="Microsoft\Data\SqlClient\SqlAuthenticationProviderManager.NetStandard.cs" />
235+
<Compile Include="Microsoft\Data\SqlClient\SqlDiagnosticListener.NetStandard.cs" />
236+
<Compile Include="Microsoft\Data\SqlClient\SqlDelegatedTransaction.NetStandard.cs" />
237+
<Compile Include="Microsoft\Data\SqlClient\TdsParser.NetStandard.cs" />
238+
</ItemGroup>
239+
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetFramework)' != 'netstandard2.0'">
240+
<Compile Include="Microsoft\Data\SqlClient\SqlColumnEncryptionEnclaveProvider.NetCoreApp.cs" />
241+
<Compile Include="Microsoft\Data\SqlClient\SqlEnclaveAttestationParameters.NetCoreApp.cs" />
242+
<Compile Include="Microsoft\Data\SqlClient\EnclaveDelegate.NetCoreApp.cs" />
243+
<Compile Include="Microsoft\Data\SqlClient\AzureAttestationBasedEnclaveProvider.cs" />
244+
<Compile Include="Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProvider.cs" />
245+
<Compile Include="Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProviderBase.cs" />
246+
<Compile Include="Microsoft\Data\SqlClient\AlwaysEncryptedAttestationException.cs" />
247+
<Compile Include="Microsoft\Data\SqlClient\AlwaysEncryptedEnclaveProviderUtils.cs" />
248+
<Compile Include="Microsoft\Data\SqlClient\EnclaveProviderBase.cs" />
249+
<Compile Include="Microsoft\Data\SqlClient\EnclaveSessionCache.cs" />
250+
</ItemGroup>
234251
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netcoreapp'">
235252
<Compile Include="Microsoft\Data\Common\DbConnectionStringCommon.NetCoreApp.cs" />
236253
<Compile Include="Microsoft\Data\ProviderBase\DbConnectionPool.NetCoreApp.cs" />
237254
<Compile Include="Microsoft\Data\SqlClient\SqlAuthenticationProviderManager.NetCoreApp.cs" />
238255
<Compile Include="Microsoft\Data\SqlClient\SqlConnectionString.NetCoreApp.cs" />
239256
<Compile Include="Microsoft\Data\SqlClient\SqlConnectionStringBuilder.NetCoreApp.cs" />
240257
<Compile Include="Microsoft\Data\SqlClient\SqlDiagnosticListener.NetCoreApp.cs" />
241-
<Compile Include="Microsoft\Data\SqlClient\SqlColumnEncryptionEnclaveProvider.NetCoreApp.cs" />
242-
<Compile Include="Microsoft\Data\SqlClient\SqlEnclaveAttestationParameters.NetCoreApp.cs" />
243-
<Compile Include="Microsoft\Data\SqlClient\EnclaveDelegate.NetCoreApp.cs" />
244258
<Compile Include="Microsoft\Data\SqlClient\SqlDelegatedTransaction.NetCoreApp.cs" />
245259
<Compile Include="Microsoft\Data\SqlClient\TdsParser.NetCoreApp.cs" />
246-
<Compile Include="Microsoft\Data\SqlClient\AzureAttestationBasedEnclaveProvider.NetCoreApp.cs" />
247-
<Compile Include="Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProvider.NetCoreApp.cs" />
248-
<Compile Include="Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProviderBase.NetCoreApp.cs" />
249-
<Compile Include="Microsoft\Data\SqlClient\AlwaysEncryptedAttestationException.NetCoreApp.cs" />
250-
<Compile Include="Microsoft\Data\SqlClient\AlwaysEncryptedEnclaveProviderUtils.NetCoreApp.cs" />
251-
<Compile Include="Microsoft\Data\SqlClient\EnclaveProviderBase.NetCoreApp.cs" />
252-
<Compile Include="Microsoft\Data\SqlClient\EnclaveSessionCache.NetCoreApp.cs" />
253260
</ItemGroup>
254261
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netcoreapp' AND '$(BuildSimulator)' == 'true'">
255262
<Compile Include="Microsoft\Data\SqlClient\SimulatorEnclaveProvider.NetCoreApp.cs" />
256263
</ItemGroup>
257-
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netstandard'">
258-
<Compile Include="Microsoft\Data\SqlClient\SqlDelegatedTransaction.NetStandard.cs" />
259-
<Compile Include="Microsoft\Data\SqlClient\TdsParser.NetStandard.cs" />
260-
</ItemGroup>
261264
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS'">
262265
<Compile Include="Microsoft\Data\SqlClient\Server\MetadataUtilsSmi.cs" />
263266
<Compile Include="Microsoft\Data\SqlClient\Server\SmiEventSink.cs" />
File renamed without changes.

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AlwaysEncryptedEnclaveProviderUtils.NetCoreApp.cs

Lines changed: 0 additions & 55 deletions
This file was deleted.
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Diagnostics;
7+
using System.Linq;
8+
using System.Security.Cryptography;
9+
10+
namespace Microsoft.Data.SqlClient
11+
{
12+
internal class EnclavePublicKey
13+
{
14+
public byte[] PublicKey { get; set; }
15+
16+
public EnclavePublicKey(byte[] payload)
17+
{
18+
PublicKey = payload;
19+
}
20+
}
21+
22+
internal class EnclaveDiffieHellmanInfo
23+
{
24+
public int Size { get; private set; }
25+
26+
public byte[] PublicKey { get; private set; }
27+
28+
public byte[] PublicKeySignature { get; private set; }
29+
30+
public EnclaveDiffieHellmanInfo(byte[] payload)
31+
{
32+
Size = payload.Length;
33+
34+
int offset = 0;
35+
int publicKeySize = BitConverter.ToInt32(payload, offset);
36+
offset += sizeof(int);
37+
38+
int publicKeySignatureSize = BitConverter.ToInt32(payload, offset);
39+
offset += sizeof(int);
40+
41+
PublicKey = payload.Skip(offset).Take(publicKeySize).ToArray();
42+
offset += publicKeySize;
43+
44+
PublicKeySignature = payload.Skip(offset).Take(publicKeySignatureSize).ToArray();
45+
offset += publicKeySignatureSize;
46+
}
47+
}
48+
49+
internal enum EnclaveType
50+
{
51+
None = 0,
52+
53+
Vbs = 1,
54+
55+
Sgx = 2
56+
}
57+
58+
// Contains methods to convert cryptography keys between different formats.
59+
internal sealed class KeyConverter
60+
{
61+
// The RSA public key blob is structured as follows:
62+
// BCRYPT_RSAKEY_BLOB header
63+
// byte[ExponentSize] publicExponent
64+
// byte[ModulusSize] modulus
65+
private readonly struct RSAPublicKeyBlob
66+
{
67+
// Size of an RSA public key blob
68+
internal static readonly int Size = 539;
69+
// Size of the BCRYPT_RSAKEY_BLOB header
70+
internal static readonly int HeaderSize = 27;
71+
// Size of the exponent (final 3 bytes of the header)
72+
internal static readonly int ExponentSize = 3;
73+
// Size of the modulus (remaining bytes after the header)
74+
internal static readonly int ModulusSize = Size - HeaderSize;
75+
internal static readonly int ExponentOffset = HeaderSize - ExponentSize;
76+
internal static readonly int ModulusOffset = HeaderSize;
77+
}
78+
79+
// Extracts the public key's modulus and exponent from an RSA public key blob
80+
// and returns an RSAParameters object
81+
internal static RSAParameters RSAPublicKeyBlobToParams(byte[] keyBlob)
82+
{
83+
Debug.Assert(keyBlob.Length == RSAPublicKeyBlob.Size,
84+
$"RSA public key blob was not the expected length. Actual: {keyBlob.Length}. Expected: {RSAPublicKeyBlob.Size}");
85+
return new RSAParameters()
86+
{
87+
Exponent = keyBlob.Skip(RSAPublicKeyBlob.ExponentOffset).Take(RSAPublicKeyBlob.ExponentSize).ToArray(),
88+
Modulus = keyBlob.Skip(RSAPublicKeyBlob.ModulusOffset).Take(RSAPublicKeyBlob.ModulusSize).ToArray()
89+
};
90+
}
91+
92+
// The ECC public key blob is structured as follows:
93+
// BCRYPT_ECCKEY_BLOB header
94+
// byte[KeySize] X
95+
// byte[KeySize] Y
96+
private readonly struct ECCPublicKeyBlob
97+
{
98+
// Size of an ECC public key blob
99+
internal static readonly int Size = 104;
100+
// Size of the BCRYPT_ECCKEY_BLOB header
101+
internal static readonly int HeaderSize = 8;
102+
// Size of each coordinate
103+
internal static readonly int KeySize = (Size - HeaderSize) / 2;
104+
}
105+
106+
// Magic numbers identifying blob types
107+
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wcce/cba27df5-4880-4f95-a879-783f8657e53b
108+
private readonly struct KeyBlobMagicNumber
109+
{
110+
internal static readonly byte[] ECDHPublicP384 = new byte[] { 0x45, 0x43, 0x4b, 0x33 };
111+
}
112+
113+
// Extracts the public key's X and Y coordinates from an ECC public key blob
114+
// and returns an ECParameters object
115+
internal static ECParameters ECCPublicKeyBlobToParams(byte[] keyBlob)
116+
{
117+
Debug.Assert(keyBlob.Length == ECCPublicKeyBlob.Size,
118+
$"ECC public key blob was not the expected length. Actual: {keyBlob.Length}. Expected: {ECCPublicKeyBlob.Size}");
119+
return new ECParameters
120+
{
121+
Curve = ECCurve.NamedCurves.nistP384,
122+
Q = new ECPoint
123+
{
124+
X = keyBlob.Skip(ECCPublicKeyBlob.HeaderSize).Take(ECCPublicKeyBlob.KeySize).ToArray(),
125+
Y = keyBlob.Skip(ECCPublicKeyBlob.HeaderSize + ECCPublicKeyBlob.KeySize).Take(ECCPublicKeyBlob.KeySize).ToArray()
126+
},
127+
};
128+
}
129+
130+
// Serializes an ECDiffieHellmanPublicKey to an ECC public key blob
131+
// "ECDiffieHellmanPublicKey.ToByteArray() doesn't have a (standards-)defined export
132+
// format. The version used by ECDiffieHellmanPublicKeyCng is Windows-specific"
133+
// from https://github.com/dotnet/runtime/issues/27276
134+
// => ECDiffieHellmanPublicKey.ToByteArray() is not supported in Unix
135+
internal static byte[] ECDHPublicKeyToECCKeyBlob(ECDiffieHellmanPublicKey publicKey)
136+
{
137+
byte[] keyBlob = new byte[ECCPublicKeyBlob.Size];
138+
139+
// Set magic number
140+
Array.Copy(KeyBlobMagicNumber.ECDHPublicP384, 0, keyBlob, 0, 4);
141+
// Set key size
142+
keyBlob[4] = (byte)ECCPublicKeyBlob.KeySize;
143+
144+
ECPoint ecPoint = publicKey.ExportParameters().Q;
145+
Debug.Assert(ecPoint.X.Length == ECCPublicKeyBlob.KeySize && ecPoint.Y.Length == ECCPublicKeyBlob.KeySize,
146+
$"ECDH public key was not the expected length. Actual (X): {ecPoint.X.Length}. Actual (Y): {ecPoint.Y.Length} Expected: {ECCPublicKeyBlob.Size}");
147+
// Copy x and y coordinates to key blob
148+
Array.Copy(ecPoint.X, 0, keyBlob, ECCPublicKeyBlob.HeaderSize, ECCPublicKeyBlob.KeySize);
149+
Array.Copy(ecPoint.Y, 0, keyBlob, ECCPublicKeyBlob.HeaderSize + ECCPublicKeyBlob.KeySize, ECCPublicKeyBlob.KeySize);
150+
return keyBlob;
151+
}
152+
}
153+
}

0 commit comments

Comments
 (0)