Пример #1
0
        private static SqlClientSymmetricKey GetKeyFromLocalProviders(SqlEncryptionKeyInfo keyInfo, SqlConnection connection, SqlCommand command)
        {
            string serverName = connection.DataSource;

            Debug.Assert(serverName is not null, @"serverName should not be null.");

            Debug.Assert(SqlConnection.ColumnEncryptionTrustedMasterKeyPaths is not null, @"SqlConnection.ColumnEncryptionTrustedMasterKeyPaths should not be null");

            ThrowIfKeyPathIsNotTrustedForServer(serverName, keyInfo.keyPath);
            if (!TryGetColumnEncryptionKeyStoreProvider(keyInfo.keyStoreName, out SqlColumnEncryptionKeyStoreProvider provider, connection, command))
            {
                throw SQL.UnrecognizedKeyStoreProviderName(keyInfo.keyStoreName,
                                                           SqlConnection.GetColumnEncryptionSystemKeyStoreProvidersNames(),
                                                           GetListOfProviderNamesThatWereSearched(connection, command));
            }

            // Decrypt the CEK
            // We will simply bubble up the exception from the DecryptColumnEncryptionKey function.
            byte[] plaintextKey;
            try
            {
                plaintextKey = provider.DecryptColumnEncryptionKey(keyInfo.keyPath, keyInfo.algorithmName, keyInfo.encryptedKey);
            }
            catch (Exception e)
            {
                // Generate a new exception and throw.
                string keyHex = GetBytesAsString(keyInfo.encryptedKey, fLast: true, countOfBytes: 10);
                throw SQL.KeyDecryptionFailed(keyInfo.keyStoreName, keyHex, e);
            }

            return(new SqlClientSymmetricKey(plaintextKey));
        }
Пример #2
0
        /// <summary>
        /// Verifies Column Master Key Signature.
        /// </summary>
        internal static void VerifyColumnMasterKeySignature(string keyStoreName, string keyPath, bool isEnclaveEnabled, byte[] CMKSignature, SqlConnection connection, SqlCommand command)
        {
            bool isValidSignature = false;

            try
            {
                Debug.Assert(SqlConnection.ColumnEncryptionTrustedMasterKeyPaths is not null,
                             @"SqlConnection.ColumnEncryptionTrustedMasterKeyPaths should not be null");

                if (CMKSignature is null || CMKSignature.Length == 0)
                {
                    throw SQL.ColumnMasterKeySignatureNotFound(keyPath);
                }

                ThrowIfKeyPathIsNotTrustedForServer(connection.DataSource, keyPath);

                // Attempt to look up the provider and verify CMK Signature
                if (!TryGetColumnEncryptionKeyStoreProvider(keyStoreName, out SqlColumnEncryptionKeyStoreProvider provider, connection, command))
                {
                    throw SQL.InvalidKeyStoreProviderName(keyStoreName,
                                                          SqlConnection.GetColumnEncryptionSystemKeyStoreProvidersNames(),
                                                          GetListOfProviderNamesThatWereSearched(connection, command));
                }

                if (ShouldUseInstanceLevelProviderFlow(keyStoreName, connection, command))
                {
                    isValidSignature = provider.VerifyColumnMasterKeyMetadata(keyPath, isEnclaveEnabled, CMKSignature);
                }
                else
                {
                    bool?signatureVerificationResult = ColumnMasterKeyMetadataSignatureVerificationCache.GetSignatureVerificationResult(keyStoreName, keyPath, isEnclaveEnabled, CMKSignature);
                    if (signatureVerificationResult is null)
                    {
                        // We will simply bubble up the exception from VerifyColumnMasterKeyMetadata function.
                        isValidSignature = provider.VerifyColumnMasterKeyMetadata(keyPath, isEnclaveEnabled,
                                                                                  CMKSignature);

                        ColumnMasterKeyMetadataSignatureVerificationCache.AddSignatureVerificationResult(keyStoreName, keyPath, isEnclaveEnabled, CMKSignature, isValidSignature);
                    }
                    else
                    {
                        isValidSignature = signatureVerificationResult.Value;
                    }
                }
            }
            catch (Exception e)
            {
                throw SQL.UnableToVerifyColumnMasterKeySignature(e);
            }

            if (!isValidSignature)
            {
                throw SQL.ColumnMasterKeySignatureVerificationFailed(keyPath);
            }
        }
        /// <summary>
        /// <para> Retrieves Symmetric Key (in plaintext) given the encryption material.</para>
        /// </summary>
        internal SqlClientSymmetricKey GetKey(SqlEncryptionKeyInfo keyInfo, SqlConnection connection, SqlCommand command)
        {
            string serverName = connection.DataSource;

            Debug.Assert(serverName is not null, @"serverName should not be null.");
            StringBuilder cacheLookupKeyBuilder = new StringBuilder(serverName, capacity: serverName.Length + SqlSecurityUtility.GetBase64LengthFromByteLength(keyInfo.encryptedKey.Length) + keyInfo.keyStoreName.Length + 2 /*separators*/);

#if DEBUG
            int capacity = cacheLookupKeyBuilder.Capacity;
#endif //DEBUG

            cacheLookupKeyBuilder.Append(":");
            cacheLookupKeyBuilder.Append(Convert.ToBase64String(keyInfo.encryptedKey));
            cacheLookupKeyBuilder.Append(":");
            cacheLookupKeyBuilder.Append(keyInfo.keyStoreName);

            string cacheLookupKey = cacheLookupKeyBuilder.ToString();

#if DEBUG
            Debug.Assert(cacheLookupKey.Length <= capacity, "We needed to allocate a larger array");
#endif //DEBUG

            // Lookup the key in cache
            if (!(_cache.Get(cacheLookupKey) is SqlClientSymmetricKey encryptionKey))
            {
                Debug.Assert(SqlConnection.ColumnEncryptionTrustedMasterKeyPaths is not null, @"SqlConnection.ColumnEncryptionTrustedMasterKeyPaths should not be null");

                SqlSecurityUtility.ThrowIfKeyPathIsNotTrustedForServer(serverName, keyInfo.keyPath);

                // Key Not found, attempt to look up the provider and decrypt CEK
                if (!SqlSecurityUtility.TryGetColumnEncryptionKeyStoreProvider(keyInfo.keyStoreName, out SqlColumnEncryptionKeyStoreProvider provider, connection, command))
                {
                    throw SQL.UnrecognizedKeyStoreProviderName(keyInfo.keyStoreName,
                                                               SqlConnection.GetColumnEncryptionSystemKeyStoreProvidersNames(),
                                                               SqlSecurityUtility.GetListOfProviderNamesThatWereSearched(connection, command));
                }

                // Decrypt the CEK
                // We will simply bubble up the exception from the DecryptColumnEncryptionKey function.
                byte[] plaintextKey;
                try
                {
                    // to prevent conflicts between CEK caches, global providers should not use their own CEK caches
                    provider.ColumnEncryptionKeyCacheTtl = new TimeSpan(0);
                    plaintextKey = provider.DecryptColumnEncryptionKey(keyInfo.keyPath, keyInfo.algorithmName, keyInfo.encryptedKey);
                }
                catch (Exception e)
                {
                    // Generate a new exception and throw.
                    string keyHex = SqlSecurityUtility.GetBytesAsString(keyInfo.encryptedKey, fLast: true, countOfBytes: 10);
                    throw SQL.KeyDecryptionFailed(keyInfo.keyStoreName, keyHex, e);
                }

                encryptionKey = new SqlClientSymmetricKey(plaintextKey);

                // If the cache TTL is zero, don't even bother inserting to the cache.
                if (SqlConnection.ColumnEncryptionKeyCacheTtl != TimeSpan.Zero)
                {
                    // In case multiple threads reach here at the same time, the first one wins.
                    // The allocated memory will be reclaimed by Garbage Collector.
                    DateTimeOffset expirationTime = DateTimeOffset.UtcNow.Add(SqlConnection.ColumnEncryptionKeyCacheTtl);
                    _cache.Add(cacheLookupKey, encryptionKey, expirationTime);
                }
            }

            return(encryptionKey);
        }