Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AE with enclaves - multi-platform and .NET Standard 2.1 support #676

Merged
merged 48 commits into from Aug 21, 2020
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
13857f2
Merge pull request #2 from dotnet/master
May 29, 2020
b807d0b
Merge remote-tracking branch 'upstream/master'
johnnypham Jun 4, 2020
26b0f35
Set up CI with Azure Pipelines
Jun 8, 2020
3da84f8
Delete azure-pipelines.yml
Jun 8, 2020
9b49213
Merge remote-tracking branch 'upstream/master'
johnnypham Jun 14, 2020
d02b69c
Set up CI with Azure Pipelines
Jun 8, 2020
896caa1
Delete azure-pipelines.yml
Jun 8, 2020
0c04741
Merge branch 'master' of https://github.com/johnnypham/SqlClient
johnnypham Jun 18, 2020
035ef3d
Merge remote-tracking branch 'upstream/master'
johnnypham Jun 21, 2020
d1dc8bb
Merge remote-tracking branch 'upstream/master'
johnnypham Jul 3, 2020
acbb0a5
Merge remote-tracking branch 'upstream/master'
johnnypham Jul 10, 2020
0d8b82f
aev2
johnnypham Jul 21, 2020
a98f2a0
azure attestation, vbs
johnnypham Jul 22, 2020
0d5c11e
Update EnclaveProviderBase.NetCoreApp.cs
johnnypham Jul 24, 2020
6eeaf13
Update EnclaveProviderBase.NetCoreApp.cs
johnnypham Jul 24, 2020
7bec0ea
replace tobytearray
johnnypham Jul 24, 2020
1831ef0
move new methods to utils
johnnypham Jul 24, 2020
b79a97e
minor changes
johnnypham Jul 27, 2020
0c898c3
ae apishould tests for linux
johnnypham Jul 29, 2020
361505a
test akv fixture
johnnypham Jul 29, 2020
c9785ea
Update SQLSetupStrategy.cs
johnnypham Jul 29, 2020
50c5b12
bulkcopyae akv test
johnnypham Jul 29, 2020
d1da600
apishould cross platform
johnnypham Jul 30, 2020
2a93a2e
test fixture changes
johnnypham Jul 30, 2020
743d6ce
Update BulkCopyAE.cs
johnnypham Jul 30, 2020
81654cc
Update BulkCopyAE.cs
johnnypham Jul 30, 2020
9ab0eac
test platform specific fixtures
johnnypham Jul 31, 2020
170ddc9
test platform specific fixtures
johnnypham Jul 31, 2020
ba1b31a
update ae tests for linux
johnnypham Jul 31, 2020
1cad3ff
minor changes
johnnypham Jul 31, 2020
daa2b13
netstandard
johnnypham Aug 4, 2020
c12121f
netstandard changes
johnnypham Aug 5, 2020
f264806
change targetframework property to targetframeworks
johnnypham Aug 5, 2020
0448362
Update SqlColumnEncryptionCertificateStoreProvider.Windows.cs
johnnypham Aug 7, 2020
9ba0fc9
Address feedback
johnnypham Aug 7, 2020
bcc7e6c
Merge branch 'aev2' of https://github.com/johnnypham/SqlClient into aev2
johnnypham Aug 7, 2020
4780d48
Merge remote-tracking branch 'upstream/master' into aev2
johnnypham Aug 7, 2020
104e0d6
fix culture exceptions in functional tests for ubuntu 18.04
johnnypham Aug 11, 2020
5575f1c
revert test changes
johnnypham Aug 11, 2020
7a1e9fb
test against .net standard 2.1
johnnypham Aug 13, 2020
5285c26
add dispose to new fixture class
johnnypham Aug 14, 2020
ec12750
Update AlwaysEncryptedEnclaveProviderUtils.cs
johnnypham Aug 18, 2020
dca6da8
Update AlwaysEncryptedEnclaveProviderUtils.cs
johnnypham Aug 18, 2020
e575519
Update AlwaysEncryptedEnclaveProviderUtils.cs
johnnypham Aug 19, 2020
50e2ee3
Merge remote-tracking branch 'upstream/master' into aev2
johnnypham Aug 20, 2020
58235f7
casing
johnnypham Aug 20, 2020
5d0fde8
Address comments
johnnypham Aug 21, 2020
a552100
Address comments
johnnypham Aug 21, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;netstandard2.0</TargetFrameworks>
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;netstandard2.0;netstandard2.1</TargetFrameworks>
<IntermediateOutputPath>$(ObjFolder)$(Configuration)\$(AssemblyName)\ref\</IntermediateOutputPath>
<OutputPath>$(BinFolder)$(Configuration)\$(AssemblyName)\ref\</OutputPath>
<DocumentationFile>$(OutputPath)\$(TargetFramework)\Microsoft.Data.SqlClient.xml</DocumentationFile>
Expand Down
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>Microsoft.Data.SqlClient</AssemblyName>
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;netstandard2.0</TargetFrameworks>
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;netstandard2.0;netstandard2.1</TargetFrameworks>
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(OSGroup)' == 'AnyOS'">Strings.PlatformNotSupported_DataSqlClient</GeneratePlatformNotSupportedAssemblyMessage>
<OSGroup Condition="'$(OSGroup)' == ''">$(OS)</OSGroup>
<TargetsWindows Condition="'$(OSGroup)'=='Windows_NT'">true</TargetsWindows>
Expand Down Expand Up @@ -226,38 +226,40 @@
<ItemGroup Condition="'$(TargetGroup)' == 'netstandard' OR '$(TargetGroup)' == 'netcoreapp' OR '$(IsUAPAssembly)' == 'true'">
<Compile Include="Microsoft.Data.SqlClient.TypeForwards.cs" />
</ItemGroup>
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netstandard'">
<Compile Include="Microsoft\Data\SqlClient\SqlAuthenticationProviderManager.NetStandard.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlDiagnosticListener.NetStandard.cs" />
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netstandard' AND '$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft\Data\SqlClient\EnclaveDelegate.NetStandard.cs" />
</ItemGroup>
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netstandard'">
<Compile Include="Microsoft\Data\SqlClient\SqlAuthenticationProviderManager.NetStandard.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlDiagnosticListener.NetStandard.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlDelegatedTransaction.NetStandard.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsParser.NetStandard.cs" />
</ItemGroup>
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetFramework)' != 'netstandard2.0'">
<Compile Include="Microsoft\Data\SqlClient\SqlColumnEncryptionEnclaveProvider.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlEnclaveAttestationParameters.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\EnclaveDelegate.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\AzureAttestationBasedEnclaveProvider.cs" />
<Compile Include="Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProvider.cs" />
<Compile Include="Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProviderBase.cs" />
<Compile Include="Microsoft\Data\SqlClient\AlwaysEncryptedAttestationException.cs" />
<Compile Include="Microsoft\Data\SqlClient\AlwaysEncryptedEnclaveProviderUtils.cs" />
<Compile Include="Microsoft\Data\SqlClient\EnclaveProviderBase.cs" />
<Compile Include="Microsoft\Data\SqlClient\EnclaveSessionCache.cs" />
</ItemGroup>
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netcoreapp'">
<Compile Include="Microsoft\Data\Common\DbConnectionStringCommon.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\ProviderBase\DbConnectionPool.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlAuthenticationProviderManager.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlConnectionString.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlConnectionStringBuilder.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlDiagnosticListener.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlColumnEncryptionEnclaveProvider.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlEnclaveAttestationParameters.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\EnclaveDelegate.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlDelegatedTransaction.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsParser.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\AzureAttestationBasedEnclaveProvider.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProvider.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProviderBase.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\AlwaysEncryptedAttestationException.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\AlwaysEncryptedEnclaveProviderUtils.NetCoreApp.cs" />
<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" />
</ItemGroup>
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS'">
<Compile Include="Microsoft\Data\SqlClient\Server\MetadataUtilsSmi.cs" />
<Compile Include="Microsoft\Data\SqlClient\Server\SmiEventSink.cs" />
Expand Down

This file was deleted.

@@ -0,0 +1,152 @@
// 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.Diagnostics;
using System.Linq;
using System.Security.Cryptography;

namespace Microsoft.Data.SqlClient
{
internal class EnclavePublicKey
{
public byte[] PublicKey { get; set; }

public EnclavePublicKey(byte[] payload)
{
PublicKey = payload;
}
}

internal class EnclaveDiffieHellmanInfo
{
public int Size { get; private set; }

public byte[] PublicKey { get; private set; }

public byte[] PublicKeySignature { get; private set; }

public EnclaveDiffieHellmanInfo(byte[] payload)
{
Size = payload.Length;

int offset = 0;
int publicKeySize = BitConverter.ToInt32(payload, offset);
offset += sizeof(int);

int publicKeySignatureSize = BitConverter.ToInt32(payload, offset);
offset += sizeof(int);

PublicKey = payload.Skip(offset).Take(publicKeySize).ToArray();
offset += publicKeySize;

PublicKeySignature = payload.Skip(offset).Take(publicKeySignatureSize).ToArray();
offset += publicKeySignatureSize;
}
}

internal enum EnclaveType
{
None = 0,

Vbs = 1,

Sgx = 2
}

// Contains methods to convert cryptography keys between different formats.
internal sealed class KeyConverter
{
// The RSA public key blob is structured as follows:
// BCRYPT_RSAKEY_BLOB header
// byte[ExponentSize] publicExponent
// byte[ModulusSize] modulus
private readonly struct RSAPublicKeyBlob
{
// Size of an RSA public key blob
internal static readonly int Size = 539;
// Size of the BCRYPT_RSAKEY_BLOB header
internal static readonly int HeaderSize = 27;
// Size of the exponent (final 3 bytes of the header)
internal static readonly int ExponentSize = 3;
// Size of the modulus (remaining bytes after the header)
internal static readonly int ModulusSize = Size - HeaderSize;
internal static readonly int ExponentOffset = HeaderSize - ExponentSize;
internal static readonly int ModulusOffset = HeaderSize;
}

// The ECC public key blob is structured as follows:
// BCRYPT_ECCKEY_BLOB header
// byte[KeySize] X
// byte[KeySize] Y
private readonly struct ECCPublicKeyBlob
{
// Size of an ECC public key blob
internal static readonly int Size = 104;
// Size of the BCRYPT_ECCKEY_BLOB header
internal static readonly int HeaderSize = 8;
// Size of each coordinate
internal static readonly int KeySize = (Size - HeaderSize) / 2;
}

// Magic numbers identifying blob types
private readonly struct KeyBlobMagicNumber
johnnypham marked this conversation as resolved.
Show resolved Hide resolved
{
internal static readonly byte[] ECDHPublicP384 = new byte[] { 0x45, 0x43, 0x4b, 0x33 };
}

// Extracts the public key's modulus and exponent from an RSA public key blob
// and returns an RSAParameters object
internal static RSAParameters RSAPublicKeyBlobToParams(byte[] keyBlob)
{
Debug.Assert(keyBlob.Length == RSAPublicKeyBlob.Size,
$"RSA public key blob was not the expected length. Actual: {keyBlob.Length}. Expected: {RSAPublicKeyBlob.Size}");
return new RSAParameters()
{
Exponent = keyBlob.Skip(RSAPublicKeyBlob.ExponentOffset).Take(RSAPublicKeyBlob.ExponentSize).ToArray(),
Modulus = keyBlob.Skip(RSAPublicKeyBlob.ModulusOffset).Take(RSAPublicKeyBlob.ModulusSize).ToArray()
};
}

// Extracts the public key's X and Y coordinates from an ECC public key blob
// and returns an ECParameters object
internal static ECParameters ECCPublicKeyBlobToParams(byte[] keyBlob)
{
Debug.Assert(keyBlob.Length == ECCPublicKeyBlob.Size,
$"ECC public key blob was not the expected length. Actual: {keyBlob.Length}. Expected: {ECCPublicKeyBlob.Size}");
return new ECParameters
{
Curve = ECCurve.NamedCurves.nistP384,
Q = new ECPoint
{
X = keyBlob.Skip(ECCPublicKeyBlob.HeaderSize).Take(ECCPublicKeyBlob.KeySize).ToArray(),
Y = keyBlob.Skip(ECCPublicKeyBlob.HeaderSize + ECCPublicKeyBlob.KeySize).Take(ECCPublicKeyBlob.KeySize).ToArray()
},
};
}

// Serializes an ECDiffieHellmanPublicKey to an ECC public key blob
// "ECDiffieHellmanPublicKey.ToByteArray() doesn't have a (standards-)defined export
// format. The version used by ECDiffieHellmanPublicKeyCng is Windows-specific"
// from https://github.com/dotnet/runtime/issues/27276
// => ECDiffieHellmanPublicKey.ToByteArray() is not supported in Unix
internal static byte[] ECDHPublicKeyToECCKeyBlob(ECDiffieHellmanPublicKey publicKey)
{
byte[] keyBlob = new byte[ECCPublicKeyBlob.Size];

// Set magic number
Array.Copy(KeyBlobMagicNumber.ECDHPublicP384, 0, keyBlob, 0, 4);
// Set key size
keyBlob[4] = (byte)ECCPublicKeyBlob.KeySize;

ECPoint ecPoint = publicKey.ExportParameters().Q;
Debug.Assert(ecPoint.X.Length == ECCPublicKeyBlob.KeySize && ecPoint.Y.Length == ECCPublicKeyBlob.KeySize,
$"ECDH public key was not the expected length. Actual (X): {ecPoint.X.Length}. Actual (Y): {ecPoint.Y.Length} Expected: {ECCPublicKeyBlob.Size}");
// Copy x and y coordinates to key blob
Array.Copy(ecPoint.X, 0, keyBlob, ECCPublicKeyBlob.HeaderSize, ECCPublicKeyBlob.KeySize);
Array.Copy(ecPoint.Y, 0, keyBlob, ECCPublicKeyBlob.HeaderSize + ECCPublicKeyBlob.KeySize, ECCPublicKeyBlob.KeySize);
return keyBlob;
}
}
}
Expand Up @@ -73,15 +73,15 @@ internal override void GetEnclaveSession(string servername, string attestationUr
// Gets the information that SqlClient subsequently uses to initiate the process of attesting the enclave and to establish a secure session with the enclave.
internal override SqlEnclaveAttestationParameters GetAttestationParameters(string attestationUrl, byte[] customData, int customDataLength)
{
ECDiffieHellmanCng clientDHKey = new ECDiffieHellmanCng(DiffieHellmanKeySize);
clientDHKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
clientDHKey.HashAlgorithm = CngAlgorithm.Sha256;
// The key derivation function and hash algorithm name are specified when key derivation is performed
ECDiffieHellman clientDHKey = ECDiffieHellman.Create();
johnnypham marked this conversation as resolved.
Show resolved Hide resolved
clientDHKey.KeySize = DiffieHellmanKeySize;
byte[] attestationParam = PrepareAttestationParameters(attestationUrl, customData, customDataLength);
return new SqlEnclaveAttestationParameters(AzureBasedAttestationProtocolId, attestationParam, 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.
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, ECDiffieHellman clientDHKey, string attestationUrl, string servername, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter)
{
sqlEnclaveSession = null;
counter = 0;
Expand Down Expand Up @@ -514,7 +514,7 @@ private void ValidateClaim(Dictionary<string, string> claims, string claimName,
}

// Derives the shared secret between the client and enclave.
private byte[] GetSharedSecret(EnclavePublicKey enclavePublicKey, byte[] nonce, EnclaveType enclaveType, EnclaveDiffieHellmanInfo enclaveDHInfo, ECDiffieHellmanCng clientDHKey)
private byte[] GetSharedSecret(EnclavePublicKey enclavePublicKey, byte[] nonce, EnclaveType enclaveType, EnclaveDiffieHellmanInfo enclaveDHInfo, ECDiffieHellman clientDHKey)
{
byte[] enclaveRsaPublicKey = enclavePublicKey.PublicKey;

Expand All @@ -529,17 +529,18 @@ private byte[] GetSharedSecret(EnclavePublicKey enclavePublicKey, byte[] nonce,
}

// Perform signature verification. The enclave's DiffieHellman public key was signed by the enclave's RSA public key.
CngKey cngkey = CngKey.Import(enclaveRsaPublicKey, CngKeyBlobFormat.GenericPublicBlob);
using (RSACng rsacng = new RSACng(cngkey))
RSAParameters rsaParams = KeyConverter.RSAPublicKeyBlobToParams(enclaveRsaPublicKey);
using (RSA rsa = RSA.Create(rsaParams))
{
if (!rsacng.VerifyData(enclaveDHInfo.PublicKey, enclaveDHInfo.PublicKeySignature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1))
if (!rsa.VerifyData(enclaveDHInfo.PublicKey, enclaveDHInfo.PublicKeySignature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1))
{
throw new ArgumentException(Strings.GetSharedSecretFailed);
}
}

CngKey key = CngKey.Import(enclaveDHInfo.PublicKey, CngKeyBlobFormat.GenericPublicBlob);
return clientDHKey.DeriveKeyMaterial(key);
ECParameters ecParams = KeyConverter.ECCPublicKeyBlobToParams(enclaveDHInfo.PublicKey);
ECDiffieHellman enclaveDHKey = ECDiffieHellman.Create(ecParams);
return clientDHKey.DeriveKeyFromHash(enclaveDHKey.PublicKey, HashAlgorithmName.SHA256);
}
#endregion
}
Expand Down