Skip to content
Open
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 @@ -124,11 +124,8 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell
// Perform Attestation per VSM protocol
VerifyAttestationInfo(enclaveSessionParameters.AttestationUrl, info.HealthReport, info.EnclaveReportPackage);

// Verify the enclave public key is bound to the signed report, before it is used for key exchange
VerifyEnclavePublicKeyBinding(info.EnclaveReportPackage, info.Identity);

// Set up shared secret and validate signature
byte[] sharedSecret = GetSharedSecret(info.Identity, info.EnclaveDHInfo, clientDHKey);
byte[] sharedSecret = GetSharedSecret(info.EnclaveReportPackage, info.Identity, info.EnclaveDHInfo, clientDHKey);

// add session to cache
sqlEnclaveSession = AddEnclaveSessionToCache(enclaveSessionParameters, sharedSecret, info.SessionId, out counter);
Expand Down Expand Up @@ -186,7 +183,7 @@ await VerifyAttestationInfoAsync(
cancellationToken).ConfigureAwait(false);

// Set up shared secret and validate signature
byte[] sharedSecret = GetSharedSecret(info.Identity, info.EnclaveDHInfo, clientDHKey);
byte[] sharedSecret = GetSharedSecret(info.EnclaveReportPackage, info.Identity, info.EnclaveDHInfo, clientDHKey);

// add session to cache
SqlEnclaveSession sqlEnclaveSession =
Expand Down Expand Up @@ -608,9 +605,15 @@ private void VerifyEnclavePolicyProperty(string property, uint actual, uint expe
}
}

// Derives the shared secret between the client and enclave.
private byte[] GetSharedSecret(EnclavePublicKey enclavePublicKey, EnclaveDiffieHellmanInfo enclaveDHInfo, ECDiffieHellman clientDHKey)
// Derives the session's shared secret from the enclave's public key, after verifying that the
// signed report commits to that key. The binding check lives here, rather than in each caller,
// so that no attestation path can derive a secret from an unbound key.
// This is internal to allow for targeted unit testing.
internal static byte[] GetSharedSecret(EnclaveReportPackage enclaveReportPackage, EnclavePublicKey enclavePublicKey, EnclaveDiffieHellmanInfo enclaveDHInfo, ECDiffieHellman clientDHKey)
{
// Verify the enclave public key is bound to the signed report, before it is used for key exchange
VerifyEnclavePublicKeyBinding(enclaveReportPackage, enclavePublicKey);

// Perform signature verification. The enclave's DiffieHellman public key was signed by the enclave's RSA public key.
using (RSA rsa = KeyConverter.CreateRSAFromPublicKeyBlob(enclavePublicKey.PublicKey))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,32 @@ public void VerifyEnclavePublicKeyBinding_SwappedKey_Throws()
Assert.Equal(Strings.VerifyEnclaveKeyBindingFailed, ex.Message);
}

/// <summary>
/// Deriving the session secret rejects an enclave public key the signed report doesn't commit
/// to, before using the key. Both the sync and async attestation paths derive the secret through
/// this method, so neither can skip the binding check; the async path did skip it when the check
/// lived in each caller.
/// </summary>
[Fact]
public void GetSharedSecret_UnboundKey_Throws()
{
// Arrange
EnclaveReportPackage testPackage = BuildReportPackage(Sha256(Encoding.UTF8.GetBytes("committed-enclave-public-key-blob")));
EnclavePublicKey substitutedKey = new EnclavePublicKey(Encoding.UTF8.GetBytes("substituted-enclave-public-key"));

// Act
// The Diffie-Hellman inputs are null: the binding check must reject the key before they are used.
Action action = () => VirtualizationBasedSecurityEnclaveProviderBase.GetSharedSecret(
testPackage,
substitutedKey,
enclaveDHInfo: null,
clientDHKey: null);

// Assert
ArgumentException ex = Assert.Throws<ArgumentException>(action);
Assert.Equal(Strings.VerifyEnclaveKeyBindingFailed, ex.Message);
}

// Builds a minimal EnclaveReportPackage whose report EnclaveData begins with the given 32-byte
// binding value. The signature is empty because this targets the binding, not the report signature.
private static EnclaveReportPackage BuildReportPackage(byte[] enclaveDataFirst32)
Expand Down