Exemple #1
0
        internal void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string enclaveAttestationUrl, out SqlEnclaveSession sqlEnclaveSession)
        {
            long counter;

            GetEnclaveSession(attestationProtocol, enclaveType, serverName, enclaveAttestationUrl, out sqlEnclaveSession, out counter, throwIfNull: false);
        }
Exemple #2
0
 // 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.
 internal 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);
 }
 // When overridden in a derived class, looks up and evicts an enclave session from the enclave session cache, if the provider implements session caching.
 internal override void InvalidateEnclaveSession(EnclaveSessionParameters enclaveSessionParameters, SqlEnclaveSession enclaveSessionToInvalidate)
 {
     InvalidateEnclaveSessionHelper(enclaveSessionParameters, enclaveSessionToInvalidate);
 }
Exemple #4
0
        internal void InvalidateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, EnclaveSessionParameters enclaveSessionParameters, SqlEnclaveSession enclaveSession)
        {
            SqlColumnEncryptionEnclaveProvider sqlColumnEncryptionEnclaveProvider = GetEnclaveProvider(attestationProtocol, enclaveType);

            sqlColumnEncryptionEnclaveProvider.InvalidateEnclaveSession(enclaveSessionParameters, enclaveSession);
        }
Exemple #5
0
        private void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, EnclaveSessionParameters enclaveSessionParameters, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength, bool throwIfNull)
        {
            SqlColumnEncryptionEnclaveProvider sqlColumnEncryptionEnclaveProvider = GetEnclaveProvider(attestationProtocol, enclaveType);

            sqlColumnEncryptionEnclaveProvider.GetEnclaveSession(enclaveSessionParameters, generateCustomData, out sqlEnclaveSession, out counter, out customData, out customDataLength);

            if (throwIfNull && sqlEnclaveSession == null)
            {
                throw SQL.NullEnclaveSessionDuringQueryExecution(enclaveType, enclaveSessionParameters.AttestationUrl);
            }
        }
Exemple #6
0
        internal void InvalidateEnclaveSession(string enclaveType, string serverName, string EnclaveAttestationUrl, SqlEnclaveSession enclaveSession)
        {
            SqlColumnEncryptionEnclaveProvider sqlColumnEncryptionEnclaveProvider = GetEnclaveProvider(enclaveType);

            sqlColumnEncryptionEnclaveProvider.InvalidateEnclaveSession(serverName, EnclaveAttestationUrl, enclaveSession);
        }
Exemple #7
0
        private void GetEnclaveSession(string enclaveType, string serverName, string enclaveAttestationUrl, out SqlEnclaveSession sqlEnclaveSession, out long counter, bool throwIfNull)
        {
            SqlColumnEncryptionEnclaveProvider sqlColumnEncryptionEnclaveProvider = GetEnclaveProvider(enclaveType);

            sqlColumnEncryptionEnclaveProvider.GetEnclaveSession(serverName, enclaveAttestationUrl, out sqlEnclaveSession, out counter);

            if (throwIfNull)
            {
                if (sqlEnclaveSession == null)
                {
                    throw SQL.NullEnclaveSessionDuringQueryExecution(enclaveType, enclaveAttestationUrl);
                }
            }
        }
Exemple #8
0
 // 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, out SqlEnclaveSession sqlEnclaveSession, out long counter)
 {
     GetEnclaveSessionHelper(servername, attestationUrl, true, out sqlEnclaveSession, out counter);
 }
 // Helper method to remove the enclave session from the cache
 protected void InvalidateEnclaveSessionHelper(EnclaveSessionParameters enclaveSessionParameters, SqlEnclaveSession enclaveSessionToInvalidate)
 {
     SessionCache.InvalidateSession(enclaveSessionParameters, enclaveSessionToInvalidate);
 }
Exemple #10
0
 /// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml' path='docs/members[@name="SqlColumnEncryptionEnclaveProvider"]/GetEnclaveSession/*'/>
 internal abstract void GetEnclaveSession(EnclaveSessionParameters enclaveSessionParameters, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength);
Exemple #11
0
 /// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml' path='docs/members[@name="SqlColumnEncryptionEnclaveProvider"]/InvalidateEnclaveSession/*'/>
 internal abstract void InvalidateEnclaveSession(EnclaveSessionParameters enclaveSessionParameters, SqlEnclaveSession enclaveSession);
 /// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml' path='docs/members[@name="SqlColumnEncryptionEnclaveProvider"]/InvalidateEnclaveSession/*'/>
 public abstract void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSession);
 /// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml' path='docs/members[@name="SqlColumnEncryptionEnclaveProvider"]/CreateEnclaveSession/*'/>
 public abstract void CreateEnclaveSession(byte[] enclaveAttestationInfo, ECDiffieHellmanCng clientDiffieHellmanKey, string attestationUrl, string servername, out SqlEnclaveSession sqlEnclaveSession, out long counter);
 /// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlColumnEncryptionEnclaveProvider.xml' path='docs/members[@name="SqlColumnEncryptionEnclaveProvider"]/GetEnclaveSession/*'/>
 public abstract void GetEnclaveSession(string serverName, string attestationUrl, out SqlEnclaveSession sqlEnclaveSession, out long counter);
 /// Performs enclave attestation, generates a symmetric key for the session, creates a an enclave session and stores the session information in the cache.
 /// <param name="enclaveAttestationInfo">The information the provider uses to attest the enclave and generate a symmetric key for the session. The format of this information is specific to the enclave attestation protocol.</param>
 /// <param name="clientDiffieHellmanKey">A Diffie-Hellman algorithm object encapsulating a client-side key pair.</param>
 /// <param name="enclaveSessionParameters">The set of parameters required for enclave session.</param>
 /// <param name="customData">The set of extra data needed for attestating the enclave.</param>
 /// <param name="customDataLength">The length of the extra data needed for attestating the enclave.</param>
 /// <param name="sqlEnclaveSession">The requested enclave session or null if the provider does not implement session caching.</param>
 /// <param name="counter">A counter that the enclave provider is expected to increment each time SqlClient retrieves the session from the cache. The purpose of this field is to prevent replay attacks.</param>
 internal abstract void CreateEnclaveSession(byte[] enclaveAttestationInfo, ECDiffieHellman clientDiffieHellmanKey, EnclaveSessionParameters enclaveSessionParameters, byte[] customData, int customDataLength,
                                             out SqlEnclaveSession sqlEnclaveSession, out long counter);
 internal void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, EnclaveSessionParameters enclaveSessionParameters, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out byte[] customData, out int customDataLength)
 {
     throw new PlatformNotSupportedException();
 }
 internal void InvalidateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string serverName, string EnclaveAttestationUrl, SqlEnclaveSession enclaveSession)
 {
     throw new PlatformNotSupportedException();
 }
 internal void InvalidateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, EnclaveSessionParameters enclaveSessionParameters, SqlEnclaveSession enclaveSession)
 {
     throw new PlatformNotSupportedException();
 }
Exemple #19
0
        internal void GetEnclaveSession(string enclaveType, string serverName, string enclaveAttestationUrl, out SqlEnclaveSession sqlEnclaveSession)
        {
            long counter;

            GetEnclaveSession(enclaveType, serverName, enclaveAttestationUrl, out sqlEnclaveSession, out counter, throwIfNull: false);
        }
        // Helper method to get the enclave session from the cache if present
        protected void GetEnclaveSessionHelper(string servername, string attestationUrl, bool shouldGenerateNonce, out SqlEnclaveSession sqlEnclaveSession, out long counter)
        {
            sqlEnclaveSession = SessionCache.GetEnclaveSession(servername, attestationUrl, out counter);
            if (sqlEnclaveSession == null)
            {
                bool sessionCacheLockTaken = false;
                bool sameThreadRetry       = false;

                // In case if on some thread we are running SQL workload which don't require attestation, then in those cases we don't want same thread to wait for event to be signaled.
                // hence skipping it
                AttestationInfoCacheItem attestationInfoCacheItem = AttestationInfoCache[Thread.CurrentThread.ManagedThreadId.ToString()] as AttestationInfoCacheItem;
                if (attestationInfoCacheItem != null)
                {
                    sameThreadRetry = true;
                }
                else
                {
                    // We are explicitly not signalling the event here, as we want to hold the event till driver calls CreateEnclaveSession
                    // If we signal the event now, then multiple thread end up calling GetAttestationParameters which triggers the attestation workflow.
                    sessionCacheLockTaken = sessionLockEvent.WaitOne(lockTimeoutInMilliseconds);

                    if (sessionCacheLockTaken)
                    {
                        lock (lockUpdateSessionLock)
                        {
                            isSessionLockAcquired = true;
                        }
                    }
                }

                // In case of multi-threaded application, first thread will set the event and all the subsequent threads will wait here either until the enclave
                // session is created or timeout happens.
                if (sessionCacheLockTaken || sameThreadRetry)
                {
                    // While the current thread is waiting for event to be signaled and in the meanwhile we already completed the attestation on different thread
                    // then we need to signal the event here
                    sqlEnclaveSession = SessionCache.GetEnclaveSession(servername, attestationUrl, out counter);
                    if (sqlEnclaveSession != null && !sameThreadRetry)
                    {
                        lock (lockUpdateSessionLock)
                        {
                            isSessionLockAcquired = false;
                            sessionLockEvent.Set();
                        }
                    }
                }
                else
                {
                    // In case if we are unable to signal the event, then it represents either
                    // 1. On other thread we have an ongoing attestation request which is taking more time may due to slow network or
                    // 2. Current workload doesn't require enclave computation due to which driver is not invoking the CreateEnclaveSession, hence sqlEnclaveSession is never set.
                    // In both cases we need to reduce the timeout to 0 so that subsequent request should not wait.
                    Interlocked.Exchange(ref lockTimeoutInMilliseconds, 0);
                }

                if (sqlEnclaveSession == null)
                {
                    if (!sameThreadRetry)
                    {
                        // Client decides to initiate the process of attesting the enclave and to establish a secure session with the enclave.
                        // To ensure that server send new attestation request instead of replaying / re-sending the old token, we will create a nonce for current attestation request.
                        byte[] nonce = new byte[NonceSize];
                        if (shouldGenerateNonce)
                        {
                            using (RandomNumberGenerator rng = new RNGCryptoServiceProvider())
                            {
                                rng.GetBytes(nonce);
                            }
                        }

                        attestationInfoCacheItem = new AttestationInfoCacheItem(attestationUrl, nonce);
                    }

                    AttestationInfoCache.Set(Thread.CurrentThread.ManagedThreadId.ToString(), attestationInfoCacheItem, DateTime.UtcNow.AddMinutes(AttestationInfoCacheTimeoutInMinutes));
                }
            }
        }
Exemple #21
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="enclavePackageBytes">byte package to be sent to enclave</param>
 /// <param name="enclaveSession"> enclave session to be used</param>
 internal EnclavePackage(byte[] enclavePackageBytes, SqlEnclaveSession enclaveSession)
 {
     EnclavePackageBytes = enclavePackageBytes;
     EnclaveSession      = enclaveSession;
 }
 // Helper method to remove the enclave session from the cache
 protected void InvalidateEnclaveSessionHelper(string servername, string attestationUrl, SqlEnclaveSession enclaveSessionToInvalidate)
 {
     SessionCache.InvalidateSession(servername, attestationUrl, enclaveSessionToInvalidate);
 }
Exemple #23
0
        internal void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, EnclaveSessionParameters enclaveSessionParameters, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out byte[] customData, out int customDataLength)
        {
            long counter;

            GetEnclaveSession(attestationProtocol, enclaveType, enclaveSessionParameters, generateCustomData, out sqlEnclaveSession, out counter, out customData, out customDataLength, throwIfNull: false);
        }
        // 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)
        {
            sqlEnclaveSession = null;
            counter           = 0;
            try
            {
                ThreadRetryCache.Remove(Thread.CurrentThread.ManagedThreadId.ToString());
                sqlEnclaveSession = GetEnclaveSessionFromCache(servername, attestationUrl, out counter);
                if (sqlEnclaveSession == null)
                {
                    if (!string.IsNullOrEmpty(attestationUrl) && customData != null && customDataLength > 0)
                    {
                        byte[] nonce = customData;

                        IdentityModelEventSource.ShowPII = true;

                        // Deserialize the payload
                        AzureAttestationInfo attestInfo = new AzureAttestationInfo(attestationInfo);

                        // Validate the attestation info
                        VerifyAzureAttestationInfo(attestationUrl, attestInfo.EnclaveType, attestInfo.AttestationToken.AttestationToken, attestInfo.Identity, nonce);

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

                        // add session to cache
                        sqlEnclaveSession = AddEnclaveSessionToCache(attestationUrl, servername, sharedSecret, attestInfo.SessionId, out counter);
                    }
                    else
                    {
                        throw new AlwaysEncryptedAttestationException(Strings.FailToCreateEnclaveSession);
                    }
                }
            }
            finally
            {
                // As per current design, we want to minimize the number of create session calls. To acheive this we block all the GetEnclaveSession calls until the first call to
                // GetEnclaveSession -> GetAttestationParameters -> CreateEnclaveSession completes or the event timeout happen.
                // Case 1: When the first request successfully creates the session, then all outstanding GetEnclaveSession will use the current session.
                // Case 2: When the first request unable to create the encalve session (may be due to some error or the first request doesn't require enclave computation) then in those case we set the event timeout to 0.
                UpdateEnclaveSessionLockStatus(sqlEnclaveSession);
            }
        }
Exemple #25
0
 // When overridden in a derived class, looks up and evicts an enclave session from the enclave session cache, if the provider implements session caching.
 internal override void InvalidateEnclaveSession(string serverName, string enclaveAttestationUrl, SqlEnclaveSession enclaveSessionToInvalidate)
 {
     InvalidateEnclaveSessionHelper(serverName, enclaveAttestationUrl, enclaveSessionToInvalidate);
 }
        // When overridden in a derived class, performs enclave attestation, generates a symmetric key for the session, creates an enclave session and stores the session information in the cache.
        internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHellman clientDHKey, EnclaveSessionParameters enclaveSessionParameters, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter)
        {
            // for None attestation: 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(enclaveSessionParameters, out counter);

                if (sqlEnclaveSession == null)
                {
                    // 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));

                    byte[] sharedSecret;
                    using ECDiffieHellman ecdh = KeyConverter.CreateECDiffieHellmanFromPublicKeyBlob(trustedModuleDHPublicKey);
                    sharedSecret = KeyConverter.DeriveKey(clientDHKey, ecdh.PublicKey);
                    long sessionId = BitConverter.ToInt64(enclaveSessionHandle, 0);
                    sqlEnclaveSession = AddEnclaveSessionToCache(enclaveSessionParameters, sharedSecret, sessionId, out counter);

                    if (sqlEnclaveSession is null)
                    {
                        throw SQL.AttestationFailed(Strings.FailToCreateEnclaveSession);
                    }
                }
            }
            finally
            {
                UpdateEnclaveSessionLockStatus(sqlEnclaveSession);
            }
        }
        // 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, ECDiffieHellman clientDHKey, EnclaveSessionParameters enclaveSessionParameters, byte[] customData, int customDataLength, out SqlEnclaveSession sqlEnclaveSession, out long counter)
        {
            sqlEnclaveSession = null;
            counter           = 0;
            try
            {
                ThreadRetryCache.Remove(Thread.CurrentThread.ManagedThreadId.ToString());
                sqlEnclaveSession = GetEnclaveSessionFromCache(enclaveSessionParameters, out counter);
                if (sqlEnclaveSession == null)
                {
                    if (!string.IsNullOrEmpty(enclaveSessionParameters.AttestationUrl))
                    {
                        // Deserialize the payload
                        AttestationInfo info = new AttestationInfo(attestationInfo);

                        // Verify enclave policy matches expected policy
                        VerifyEnclavePolicy(info.EnclaveReportPackage);

                        // Perform Attestation per VSM protocol
                        VerifyAttestationInfo(enclaveSessionParameters.AttestationUrl, info.HealthReport, info.EnclaveReportPackage);

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

                        // add session to cache
                        sqlEnclaveSession = AddEnclaveSessionToCache(enclaveSessionParameters, sharedSecret, info.SessionId, out counter);
                    }
                    else
                    {
                        throw new AlwaysEncryptedAttestationException(Strings.FailToCreateEnclaveSession);
                    }
                }
            }
            finally
            {
                UpdateEnclaveSessionLockStatus(sqlEnclaveSession);
            }
        }
Exemple #28
0
        // 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 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.
 internal override void GetEnclaveSession(EnclaveSessionParameters enclaveSessionParameters, bool generateCustomData, out SqlEnclaveSession sqlEnclaveSession, out long counter, out byte[] customData, out int customDataLength)
 {
     GetEnclaveSessionHelper(enclaveSessionParameters, false, out sqlEnclaveSession, out counter, out customData, out customDataLength);
 }
 /// Performs enclave attestation, generates a symmetric key for the session, creates a an enclave session and stores the session information in the cache.
 /// <param name="enclaveAttestationInfo">The information the provider uses to attest the enclave and generate a symmetric key for the session. The format of this information is specific to the enclave attestation protocol.</param>
 /// <param name="clientDiffieHellmanKey">A Diffie-Hellman algorithm object encapsulating a client-side key pair.</param>
 /// <param name="attestationUrl">The endpoint of an attestation service for attesting the enclave.</param>
 /// <param name="servername">The name of the SQL Server instance containing the enclave.</param>
 /// <param name="customData">The set of extra data needed for attestating the enclave.</param>
 /// <param name="customDataLength">The length of the extra data needed for attestating the enclave.</param>
 /// <param name="sqlEnclaveSession">The requested enclave session or null if the provider does not implement session caching.</param>
 /// <param name="counter">A counter that the enclave provider is expected to increment each time SqlClient retrieves the session from the cache. The purpose of this field is to prevent replay attacks.</param>
 internal abstract void CreateEnclaveSession(byte[] enclaveAttestationInfo, ECDiffieHellmanCng clientDiffieHellmanKey, string attestationUrl, string servername, byte[] customData, int customDataLength,
                                             out SqlEnclaveSession sqlEnclaveSession, out long counter);