From b1d37209c76254d795518c6e9053b202197bb25d Mon Sep 17 00:00:00 2001 From: Lawrence LCI Date: Mon, 25 Oct 2021 11:21:38 -0700 Subject: [PATCH 01/25] Add test coverage to SqlCollation for FirstSupportedCollationVersion and to verify out of range for LocaleId --- .../tests/FunctionalTests/SqlParameterTest.cs | 63 +++++++++++++++++-- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs index 344a578b4a..e35a34f939 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs @@ -659,13 +659,68 @@ public void InferType_DateTimeOffset() Assert.Equal(DbType.DateTimeOffset, param.DbType); } + [Theory] + [InlineData(15)] + [InlineData(1044)] + [InlineData(1047)] + [InlineData(1056)] + [InlineData(1065)] + [InlineData(1068)] + [InlineData(1070)] + [InlineData(1071)] + [InlineData(1081)] + [InlineData(1082)] + [InlineData(1083)] + [InlineData(1087)] + [InlineData(1090)] + [InlineData(1091)] + [InlineData(1092)] + [InlineData(1093)] + [InlineData(1101)] + [InlineData(1105)] + [InlineData(1106)] + [InlineData(1107)] + [InlineData(1108)] + [InlineData(1114)] + [InlineData(1121)] + [InlineData(1122)] + [InlineData(1123)] + [InlineData(1125)] + [InlineData(1133)] + [InlineData(1146)] + [InlineData(1148)] + [InlineData(1150)] + [InlineData(1152)] + [InlineData(1153)] + [InlineData(1155)] + [InlineData(1157)] + [InlineData(1164)] + [InlineData(2074)] + [InlineData(2092)] + [InlineData(2107)] + [InlineData(2143)] + [InlineData(3076)] + [InlineData(3098)] + [InlineData(5124)] + [InlineData(5146)] + [InlineData(8218)] + public void LocaleId(int lcid) + { + // To verify all the cases in SqlCollation.FirstSupportedCollationVersion + SqlParameter parameter = new SqlParameter(); + Assert.Equal(0, parameter.LocaleId); + parameter.LocaleId = lcid; + Assert.Equal(parameter.LocaleId, lcid); + } + [Fact] - public void LocaleId() + public void LocaleIdOutOfRange_Throws() { SqlParameter parameter = new SqlParameter(); - Assert.Equal(0, parameter.LocaleId); - parameter.LocaleId = 15; - Assert.Equal(15, parameter.LocaleId); + ArgumentOutOfRangeException ex = Assert.Throws(() => { parameter.LocaleId = -1; }); + Assert.NotNull(ex); + Assert.NotNull(ex.ParamName); + Assert.Contains("LocaleId", ex.ParamName, StringComparison.OrdinalIgnoreCase); } [Fact] From 02a65c67c21db9297c4f66ea9939173a4f5826a8 Mon Sep 17 00:00:00 2001 From: Lawrence LCI Date: Mon, 25 Oct 2021 20:20:21 -0700 Subject: [PATCH 02/25] Add tests to SqlConnectionStringBuilder to all properties that throws an exception --- .../SqlConnectionStringBuilderTest.cs | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs index bf08250e83..1252cdf3f0 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs @@ -101,6 +101,196 @@ public void ConnectionStringTestsNetFx(string connectionString) ExecuteConnectionStringTests(connectionString); } + [Fact] + public void SetInvalidApplicationIntent_Throws() + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + + ApplicationIntent invalid = (ApplicationIntent)Enum.GetValues(typeof(ApplicationIntent)).Length + 1; + ArgumentOutOfRangeException ex = Assert.Throws(() => builder.ApplicationIntent = invalid); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("ApplicationIntent", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void SetInvalidAttestationProtocol_Throws() + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + + SqlConnectionAttestationProtocol invalid = (SqlConnectionAttestationProtocol)Enum.GetValues(typeof(SqlConnectionAttestationProtocol)).Length + 1; + ArgumentOutOfRangeException ex = Assert.Throws(() => builder.AttestationProtocol = invalid); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("SqlConnectionAttestationProtocol", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void SetInvalidAuthentication_Throws() + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + + SqlAuthenticationMethod invalid = (SqlAuthenticationMethod)Enum.GetValues(typeof(SqlAuthenticationMethod)).Length + 1; + ArgumentOutOfRangeException ex = Assert.Throws(() => builder.Authentication = invalid); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("SqlAuthenticationMethod", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void SetInvalidColumnEncryptionSetting_Throws() + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + + SqlConnectionColumnEncryptionSetting invalid = (SqlConnectionColumnEncryptionSetting)Enum.GetValues(typeof(SqlConnectionColumnEncryptionSetting)).Length + 1; + ArgumentOutOfRangeException ex = Assert.Throws(() => builder.ColumnEncryptionSetting = invalid); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("SqlConnectionColumnEncryptionSetting", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void SetInvalidConnectTimeout_Throws() + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + + ArgumentException ex = Assert.Throws(() => builder.ConnectTimeout = -1); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("connect timeout", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void SetInvalidCommandTimeout_Throws() + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + + ArgumentException ex = Assert.Throws(() => builder.CommandTimeout = -1); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("command timeout", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Theory] + [InlineData(-1)] + [InlineData(256)] + public void SetInvalidConnectRetryCount_Throws(int invalid) + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + + ArgumentException ex = Assert.Throws(() => builder.ConnectRetryCount = invalid); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("connect retry count", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Theory] + [InlineData(-1)] + [InlineData(256)] + public void SetInvalidConnectRetryInterval_Throws(int invalid) + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + + ArgumentException ex = Assert.Throws(() => builder.ConnectRetryInterval = invalid); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("connect retry interval", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void SetInvalidIPAddressPreference_Throws() + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + + SqlConnectionIPAddressPreference invalid = (SqlConnectionIPAddressPreference)Enum.GetValues(typeof(SqlConnectionIPAddressPreference)).Length + 1; + ArgumentOutOfRangeException ex = Assert.Throws(() => builder.IPAddressPreference = invalid); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("SqlConnectionIPAddressPreference", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void SetInvalidPoolBlockingPeriod_Throws() + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + + PoolBlockingPeriod invalid = (PoolBlockingPeriod)Enum.GetValues(typeof(PoolBlockingPeriod)).Length + 1; + ArgumentOutOfRangeException ex = Assert.Throws(() => builder.PoolBlockingPeriod = invalid); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("PoolBlockingPeriod", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void SetInvalidLoadBalanceTimeout_Throws() + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + + ArgumentException ex = Assert.Throws(() => builder.LoadBalanceTimeout = -1); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("load balance timeout", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void SetInvalidMaxPoolSize_Throws() + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + + ArgumentException ex = Assert.Throws(() => builder.MaxPoolSize = 0); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("max pool size", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void SetInvalidMinPoolSize_Throws() + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + + ArgumentException ex = Assert.Throws(() => builder.MinPoolSize = -1); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("min pool size", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Theory] + [InlineData(0)] + [InlineData(511)] + [InlineData(32769)] + [InlineData(int.MaxValue)] + public void SetInvalidPacketSize_Throws(int invalid) + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + + ArgumentException ex = Assert.Throws(() => builder.PacketSize = invalid); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("packet size", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Theory] + [InlineData("AttachDBFilename","somefile.db")] + public void SetKeyword(string keyword, string value) + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + builder[keyword] = value; + Assert.Equal(builder[keyword], value); + } + + [Fact] + public void SetNotSupportedKeyword_Throws() + { + // We may want to remove the unreachable code path for default in the GetIndex(keyword) method already throws UnsupportedKeyword + // so default: throw UnsupportedKeyword(keyword) is never reached unless it's a supported keyword, but it's not handled in the switch case. + + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + ArgumentException ex = Assert.Throws(() => builder["NotSupported"] = "not important"); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("not supported", ex.Message, StringComparison.OrdinalIgnoreCase); + } + [Fact] public void UnexpectedKeywordRetrieval() { From 16c0a64070549d91b2069ed475aa3132e03176f9 Mon Sep 17 00:00:00 2001 From: Lawrence LCI Date: Tue, 26 Oct 2021 13:20:13 -0700 Subject: [PATCH 03/25] Add a test cases for SqlClientLogger for code coverage --- .../Microsoft.Data.SqlClient.Tests.csproj | 1 + .../FunctionalTests/SqlClientLoggerTest.cs | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlClientLoggerTest.cs diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index 15032653d6..49ae675022 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -28,6 +28,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlClientLoggerTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlClientLoggerTest.cs new file mode 100644 index 0000000000..3617882b42 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlClientLoggerTest.cs @@ -0,0 +1,40 @@ +// 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 Xunit; + +namespace Microsoft.Data.SqlClient.Tests +{ + public class SqlClientLoggerTest + { + [Fact] + public void LogWarning() + { + // There is not much to test here but to add the code coverage. + SqlClientLogger logger = new(); + logger.LogWarning("test type", "test method", "test message"); + } + + [Fact] + public void LogAssert() + { + SqlClientLogger logger = new(); + logger.LogAssert(true, "test type", "test method", "test message"); + } + + [Fact] + public void LogError() + { + SqlClientLogger logger = new(); + logger.LogError("test type", "test method", "test message"); + } + + [Fact] + public void LogInfo() + { + SqlClientLogger logger = new(); + logger.LogInfo("test type", "test method", "test message"); + } + } +} From 60172e485db3b72abd9cc1d401bf4202c32caf0a Mon Sep 17 00:00:00 2001 From: Lawrence LCI Date: Tue, 26 Oct 2021 16:44:22 -0700 Subject: [PATCH 04/25] Add code coverage for SqlClientFactory covering CreateDataSourceEnumerator and GetService for netfx and CreateCommandBuilder for both --- .../FunctionalTests/SqlClientFactoryTest.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlClientFactoryTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlClientFactoryTest.cs index 15b7222df9..f0e8d39173 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlClientFactoryTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlClientFactoryTest.cs @@ -3,6 +3,8 @@ // See the LICENSE file in the project root for more information. using System; +using System.Data.Sql; +using System.Reflection; using Xunit; namespace Microsoft.Data.SqlClient.Tests @@ -20,6 +22,7 @@ public void InstanceTest() public static readonly object[][] FactoryMethodTestData = { new object[] { new Func(SqlClientFactory.Instance.CreateCommand), typeof(SqlCommand) }, + new object[] { new Func(SqlClientFactory.Instance.CreateCommandBuilder), typeof(SqlCommandBuilder) }, new object[] { new Func(SqlClientFactory.Instance.CreateConnection), typeof(SqlConnection) }, new object[] { new Func(SqlClientFactory.Instance.CreateConnectionStringBuilder), typeof(SqlConnectionStringBuilder) }, new object[] { new Func(SqlClientFactory.Instance.CreateDataAdapter), typeof(SqlDataAdapter) }, @@ -40,5 +43,26 @@ public void FactoryMethodTest(Func factory, Type expectedType) Assert.NotSame(value1, value2); } + +#if NETFRAMEWORK + [Fact] + public void FactoryCreateDataSourceEnumerator() + { + // Unable to cover the in the FactoryMethodTest because the SqlDataSourceEnumerator is a singleton so, it's always the same. + object instance = SqlClientFactory.Instance.CreateDataSourceEnumerator(); + // SqlDataSourceEnumerator is not available for .NET core 3.1 and above, so the type check is only for .NET Framework. + Assert.IsType(instance); + Assert.NotNull(instance); + } + + [Fact] + public void FactoryGetService() + { + Type type = typeof(SqlClientFactory); + MethodInfo method = type.GetMethod("System.IServiceProvider.GetService", BindingFlags.NonPublic | BindingFlags.Instance); + object res = method.Invoke(SqlClientFactory.Instance, new object[] { null }); + Assert.Null(res); + } +#endif } } From 296049b2e14b19cb29f668b3235c204f5e3e2399 Mon Sep 17 00:00:00 2001 From: Lawrence LCI Date: Wed, 27 Oct 2021 11:00:21 -0700 Subject: [PATCH 05/25] Add tests to SqlParameterCollection for code coverage --- .../Microsoft.Data.SqlClient.Tests.csproj | 1 + .../SqlParameterCollectionTest.cs | 118 ++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterCollectionTest.cs diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index 49ae675022..fa4b67aab3 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -48,6 +48,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterCollectionTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterCollectionTest.cs new file mode 100644 index 0000000000..a67e642704 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterCollectionTest.cs @@ -0,0 +1,118 @@ +// 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 Xunit; + +namespace Microsoft.Data.SqlClient.Tests +{ + public class SqlParameterCollectionTest + { + [Fact] + public void CollectionAddInvalidRange_Throws() + { + SqlCommand command = new SqlCommand(); + SqlParameterCollection collection = command.Parameters; + + Array invalid = null; + ArgumentNullException ex = Assert.Throws(() => collection.AddRange(invalid)); + Assert.NotNull(ex); + } + + [Fact] + public void CollectionAddRange() + { + SqlCommand command = new SqlCommand(); + SqlParameterCollection collection = command.Parameters; + Array sqlParameters = new SqlParameter[] { new("Test1", 1), new("Test2", 2) }; + + collection.AddRange(sqlParameters); + + Assert.Equal(2, collection.Count); + Assert.Equal((SqlParameter)sqlParameters.GetValue(0), collection[0]); + Assert.Equal((SqlParameter)sqlParameters.GetValue(1), collection[1]); + } + + [Fact] + public void CollectionCheckNameInvalid_Throws() + { + SqlCommand command = new SqlCommand(); + SqlParameterCollection collection = command.Parameters; + collection.Add(new SqlParameter("Test1", 1)); + collection.Add(new SqlParameter("Test2", 2)); + + IndexOutOfRangeException ex = Assert.Throws(() => collection.RemoveAt("DoesNotExist")); + Assert.NotNull(ex); + Assert.NotEmpty(ex.Message); + Assert.Contains("DoesNotExist", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void ConnectionCopyTo() + { + SqlCommand command = new SqlCommand(); + SqlParameterCollection collection = command.Parameters; + collection.Add(new SqlParameter("Test1", 1)); + collection.Add(new SqlParameter("Test2", 2)); + + SqlParameter[] copied = new SqlParameter[2]; + collection.CopyTo(copied, 0); + + Assert.Equal(collection[0], copied[0]); + Assert.Equal(collection[1], copied[1]); + } + + [Fact] + public void CollectionIndexOfCaseInsensitive() + { + SqlCommand command = new SqlCommand(); + SqlParameterCollection collection = command.Parameters; + collection.Add(new SqlParameter("TEST1", 1)); + collection.Add(new SqlParameter("Test2", 2)); + collection.Add(new SqlParameter("Test3", 3)); + + int index = collection.IndexOf("test1"); + Assert.Equal(0, index); + } + + [Fact] + public void CollectionRemove() + { + SqlCommand command = new SqlCommand(); + SqlParameterCollection collection = command.Parameters; + SqlParameter parameter1 = new SqlParameter("Test1", 1); + collection.Add(parameter1); + collection.Add(new SqlParameter("Test2", 2)); + collection.Add(new SqlParameter("Test3", 3)); + + collection.Remove(parameter1); + Assert.Equal(2, collection.Count); + Assert.Equal("Test2", collection[0].ParameterName); + } + + [Fact] + public void CollectionSetParameter() + { + SqlCommand command = new SqlCommand(); + SqlParameterCollection collection = command.Parameters; + collection.Add(new SqlParameter("TestOne", 0)); + collection.Add(new SqlParameter("Test2", 2)); + collection.Add(new SqlParameter("Test3", 3)); + + collection[0] = new SqlParameter("Test1", 1); + Assert.Equal("Test1", collection[0].ParameterName); + Assert.Equal(1, (int)collection[0].Value); + } + + [Fact] + public void CollectionValiateNull_Throws() + { + SqlCommand command = new SqlCommand(); + SqlParameterCollection collection = command.Parameters; + + ArgumentNullException ex = Assert.Throws(() => collection.Add(null)); + Assert.NotNull(ex); + } + } +} From 2d57ffe9e3214b3e2fef6282c31fb8fd903500eb Mon Sep 17 00:00:00 2001 From: Lawrence LCI Date: Fri, 29 Oct 2021 16:33:18 -0700 Subject: [PATCH 06/25] Add missing code coverage to SqlCommandSet --- .../Microsoft.Data.SqlClient.Tests.csproj | 1 + .../FunctionalTests/SqlCommandSetTest.cs | 184 ++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlCommandSetTest.cs diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index fa4b67aab3..97336390d6 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -29,6 +29,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlCommandSetTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlCommandSetTest.cs new file mode 100644 index 0000000000..b0c357e19b --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlCommandSetTest.cs @@ -0,0 +1,184 @@ +using System; +using System.Data; +using System.Reflection; +using Xunit; + +namespace Microsoft.Data.SqlClient.Tests +{ + public class SqlCommandSetTest + { + private static Assembly mds = Assembly.GetAssembly(typeof(SqlConnection)); + + [Theory] + [InlineData("BatchCommand")] + [InlineData("CommandList")] + public void GetDisposedProperty_Throws(string propertyName) + { + var cmdSet = CreateInstance(); + CallMethod(cmdSet, "Dispose"); + Exception ex = GetProperty_Throws(cmdSet, propertyName); + VerifyException(ex, "disposed"); + } + + [Fact] + public void AppendCommandWithEmptyString_Throws() + { + var cmdSet = CreateInstance(); + SqlCommand cmd = new SqlCommand(""); + Exception ex = CallMethod_Throws(cmdSet, "Append", cmd); + VerifyException(ex, "CommandText property has not been initialized"); + } + + [Theory] + [InlineData(CommandType.TableDirect)] + [InlineData((CommandType)5)] + public void AppendBadCommandType_Throws(CommandType commandType) + { + var cmdSet = CreateInstance(); + SqlCommand cmd = GenerateBadCommand(commandType); + Exception ex = CallMethod_Throws(cmdSet, "Append", cmd); + VerifyException(ex, "CommandType"); + } + + [Fact] + public void AppendBadParameterName_Throws() + { + var cmdSet = CreateInstance(); + SqlCommand cmd = new SqlCommand("Test"); + cmd.CommandType = CommandType.Text; + cmd.Parameters.Add(new SqlParameter("Test1;=", "1")); + Exception ex = CallMethod_Throws(cmdSet, "Append", cmd); + VerifyException(ex, "not valid"); + } + + [Theory] + [InlineData(new byte[] { 1, 2, 3 })] + [InlineData(new char[] { '1', '2', '3' })] + public void AppendParameterArrayWithSize(object array) + { + var cmdSet = CreateInstance(); + SqlCommand cmd = new SqlCommand("Test"); + cmd.CommandType = CommandType.StoredProcedure; + SqlParameter parameter = new SqlParameter("@array", array); + parameter.Size = 2; + cmd.Parameters.Add(parameter); + CallMethod(cmdSet, "Append", cmd); + object p = CallMethod(cmdSet, "GetParameter", 0, 0); + SqlParameter result = p as SqlParameter; + Assert.NotNull(result); + Assert.Equal("@array", result.ParameterName); + Assert.Equal(2, result.Size); + } + + [Fact] + public void GetParameter() + { + var cmdSet = CreateInstance(); + SqlCommand cmd = new SqlCommand("Test"); + cmd.CommandType = CommandType.Text; + cmd.Parameters.Add(new SqlParameter("@text", "value")); + CallMethod(cmdSet, "Append", cmd); + object p = CallMethod(cmdSet, "GetParameter", 0, 0); + SqlParameter result = p as SqlParameter; + Assert.NotNull(result); + Assert.Equal("@text", result.ParameterName); + Assert.Equal("value", (string)result.Value); + } + + [Fact] + public void GetParameterCount() + { + var commandSetType = mds.GetType("Microsoft.Data.SqlClient.SqlCommandSet"); + var cmdSet = Activator.CreateInstance(commandSetType, true); + SqlCommand cmd = new SqlCommand("Test"); + cmd.CommandType = CommandType.Text; + cmd.Parameters.Add(new SqlParameter("@abc", "1")); + cmd.Parameters.Add(new SqlParameter("@test", "2")); + commandSetType.GetMethod("Append", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(cmdSet, new object[] { cmd }); + int index = 0; + int count = (int)commandSetType.GetMethod("GetParameterCount", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(cmdSet, new object[] { index }); + Assert.Equal(2, count); + } + + [Fact] + public void InvalidCommandBehaviorValidateCommandBehavior_Throws() + { + var cmdSet = CreateInstance(); + Exception ex = CallMethod_Throws(cmdSet, "ValidateCommandBehavior", "ExecuteNonQuery", (CommandBehavior)64); + VerifyException(ex, "CommandBehavior"); + } + + [Fact] + public void NotSupportedCommandBehaviorValidateCommandBehavior_Throws() + { + var cmdSet = CreateInstance(); + Exception ex = CallMethod_Throws(cmdSet, "ValidateCommandBehavior", "ExecuteNonQuery", CommandBehavior.KeyInfo); + VerifyException(ex, "not supported"); + } + + #region private methods + + private object CallMethod(object instance, string methodName, params object[] values) + { + var commandSetType = mds.GetType("Microsoft.Data.SqlClient.SqlCommandSet"); + object returnValue = commandSetType.GetMethod(methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(instance, values); + return returnValue; + } + + private object CallMethod(object instance, string methodName) + { + var commandSetType = mds.GetType("Microsoft.Data.SqlClient.SqlCommandSet"); + object returnValue = commandSetType.GetMethod(methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(instance, new object[] { }); + return returnValue; + } + + private Exception CallMethod_Throws(object instance, string methodName, params object[] values) + { + var commandSetType = mds.GetType("Microsoft.Data.SqlClient.SqlCommandSet"); + Exception ex = Assert.ThrowsAny(() => + { + commandSetType.GetMethod(methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(instance, values); + }); + return ex; + } + + private object CreateInstance() + { + var commandSetType = mds.GetType("Microsoft.Data.SqlClient.SqlCommandSet"); + object cmdSet = Activator.CreateInstance(commandSetType, true); + return cmdSet; + } + + private Exception GetProperty_Throws(object instance, string propertyName) + { + var commandSetType = mds.GetType("Microsoft.Data.SqlClient.SqlCommandSet"); + var cmdSet = instance; + Exception ex = Assert.ThrowsAny(() => + { + commandSetType.GetProperty(propertyName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetGetMethod(true).Invoke(cmdSet, new object[] { }); + }); + + return ex; + } + + private SqlCommand GenerateBadCommand(CommandType cType) + { + SqlCommand cmd = new SqlCommand("Test"); + Type sqlCommandType = cmd.GetType(); + // There's validation done on the CommandType property, but we need to create one that avoids the check for the test case. + sqlCommandType.GetField("_commandType", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(cmd, cType); + + return cmd; + } + + private void VerifyException(Exception ex, string contains) + { + Assert.NotNull(ex); + Assert.IsType(ex.InnerException); + Assert.NotNull(ex.InnerException); + Assert.NotEmpty(ex.InnerException.Message); + Assert.Contains(contains, ex.InnerException.Message, StringComparison.OrdinalIgnoreCase); + } + #endregion + } +} From 8b5ee2132d20021334467c8e43fcb131420675a1 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Wed, 17 Nov 2021 12:44:09 -0800 Subject: [PATCH 07/25] remove unnecessary asserts --- .../netfx/src/Microsoft.Data.SqlClient.csproj | 1 + .../FunctionalTests/SqlCommandSetTest.cs | 2 -- .../SqlConnectionStringBuilderTest.cs | 30 ------------------- .../SqlParameterCollectionTest.cs | 8 ++--- .../tests/FunctionalTests/SqlParameterTest.cs | 1 - 5 files changed, 3 insertions(+), 39 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index df8e73b2d3..d6f95e6910 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -338,6 +338,7 @@ Microsoft\Data\SqlClient\SqlCommandBuilder.cs + Component Microsoft\Data\SqlClient\SqlCommandSet.cs diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlCommandSetTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlCommandSetTest.cs index b0c357e19b..1428bcc3e8 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlCommandSetTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlCommandSetTest.cs @@ -175,8 +175,6 @@ private void VerifyException(Exception ex, string contains) { Assert.NotNull(ex); Assert.IsType(ex.InnerException); - Assert.NotNull(ex.InnerException); - Assert.NotEmpty(ex.InnerException.Message); Assert.Contains(contains, ex.InnerException.Message, StringComparison.OrdinalIgnoreCase); } #endregion diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs index 1252cdf3f0..d80875af80 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs @@ -108,8 +108,6 @@ public void SetInvalidApplicationIntent_Throws() ApplicationIntent invalid = (ApplicationIntent)Enum.GetValues(typeof(ApplicationIntent)).Length + 1; ArgumentOutOfRangeException ex = Assert.Throws(() => builder.ApplicationIntent = invalid); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("ApplicationIntent", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -120,8 +118,6 @@ public void SetInvalidAttestationProtocol_Throws() SqlConnectionAttestationProtocol invalid = (SqlConnectionAttestationProtocol)Enum.GetValues(typeof(SqlConnectionAttestationProtocol)).Length + 1; ArgumentOutOfRangeException ex = Assert.Throws(() => builder.AttestationProtocol = invalid); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("SqlConnectionAttestationProtocol", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -132,8 +128,6 @@ public void SetInvalidAuthentication_Throws() SqlAuthenticationMethod invalid = (SqlAuthenticationMethod)Enum.GetValues(typeof(SqlAuthenticationMethod)).Length + 1; ArgumentOutOfRangeException ex = Assert.Throws(() => builder.Authentication = invalid); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("SqlAuthenticationMethod", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -144,8 +138,6 @@ public void SetInvalidColumnEncryptionSetting_Throws() SqlConnectionColumnEncryptionSetting invalid = (SqlConnectionColumnEncryptionSetting)Enum.GetValues(typeof(SqlConnectionColumnEncryptionSetting)).Length + 1; ArgumentOutOfRangeException ex = Assert.Throws(() => builder.ColumnEncryptionSetting = invalid); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("SqlConnectionColumnEncryptionSetting", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -155,8 +147,6 @@ public void SetInvalidConnectTimeout_Throws() SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); ArgumentException ex = Assert.Throws(() => builder.ConnectTimeout = -1); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("connect timeout", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -166,8 +156,6 @@ public void SetInvalidCommandTimeout_Throws() SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); ArgumentException ex = Assert.Throws(() => builder.CommandTimeout = -1); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("command timeout", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -179,8 +167,6 @@ public void SetInvalidConnectRetryCount_Throws(int invalid) SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); ArgumentException ex = Assert.Throws(() => builder.ConnectRetryCount = invalid); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("connect retry count", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -192,8 +178,6 @@ public void SetInvalidConnectRetryInterval_Throws(int invalid) SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); ArgumentException ex = Assert.Throws(() => builder.ConnectRetryInterval = invalid); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("connect retry interval", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -204,8 +188,6 @@ public void SetInvalidIPAddressPreference_Throws() SqlConnectionIPAddressPreference invalid = (SqlConnectionIPAddressPreference)Enum.GetValues(typeof(SqlConnectionIPAddressPreference)).Length + 1; ArgumentOutOfRangeException ex = Assert.Throws(() => builder.IPAddressPreference = invalid); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("SqlConnectionIPAddressPreference", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -216,8 +198,6 @@ public void SetInvalidPoolBlockingPeriod_Throws() PoolBlockingPeriod invalid = (PoolBlockingPeriod)Enum.GetValues(typeof(PoolBlockingPeriod)).Length + 1; ArgumentOutOfRangeException ex = Assert.Throws(() => builder.PoolBlockingPeriod = invalid); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("PoolBlockingPeriod", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -227,8 +207,6 @@ public void SetInvalidLoadBalanceTimeout_Throws() SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); ArgumentException ex = Assert.Throws(() => builder.LoadBalanceTimeout = -1); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("load balance timeout", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -238,8 +216,6 @@ public void SetInvalidMaxPoolSize_Throws() SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); ArgumentException ex = Assert.Throws(() => builder.MaxPoolSize = 0); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("max pool size", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -249,8 +225,6 @@ public void SetInvalidMinPoolSize_Throws() SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); ArgumentException ex = Assert.Throws(() => builder.MinPoolSize = -1); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("min pool size", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -264,8 +238,6 @@ public void SetInvalidPacketSize_Throws(int invalid) SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); ArgumentException ex = Assert.Throws(() => builder.PacketSize = invalid); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("packet size", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -286,8 +258,6 @@ public void SetNotSupportedKeyword_Throws() SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); ArgumentException ex = Assert.Throws(() => builder["NotSupported"] = "not important"); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("not supported", ex.Message, StringComparison.OrdinalIgnoreCase); } diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterCollectionTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterCollectionTest.cs index a67e642704..e93dbcc196 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterCollectionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterCollectionTest.cs @@ -16,8 +16,7 @@ public void CollectionAddInvalidRange_Throws() SqlParameterCollection collection = command.Parameters; Array invalid = null; - ArgumentNullException ex = Assert.Throws(() => collection.AddRange(invalid)); - Assert.NotNull(ex); + Assert.Throws(() => collection.AddRange(invalid)); } [Fact] @@ -43,8 +42,6 @@ public void CollectionCheckNameInvalid_Throws() collection.Add(new SqlParameter("Test2", 2)); IndexOutOfRangeException ex = Assert.Throws(() => collection.RemoveAt("DoesNotExist")); - Assert.NotNull(ex); - Assert.NotEmpty(ex.Message); Assert.Contains("DoesNotExist", ex.Message, StringComparison.OrdinalIgnoreCase); } @@ -111,8 +108,7 @@ public void CollectionValiateNull_Throws() SqlCommand command = new SqlCommand(); SqlParameterCollection collection = command.Parameters; - ArgumentNullException ex = Assert.Throws(() => collection.Add(null)); - Assert.NotNull(ex); + Assert.Throws(() => collection.Add(null)); } } } diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs index e35a34f939..2f29b1bd15 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs @@ -718,7 +718,6 @@ public void LocaleIdOutOfRange_Throws() { SqlParameter parameter = new SqlParameter(); ArgumentOutOfRangeException ex = Assert.Throws(() => { parameter.LocaleId = -1; }); - Assert.NotNull(ex); Assert.NotNull(ex.ParamName); Assert.Contains("LocaleId", ex.ParamName, StringComparison.OrdinalIgnoreCase); } From b0ba491c3deed57809682483fadb9cdb81f79cb4 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Wed, 17 Nov 2021 12:44:41 -0800 Subject: [PATCH 08/25] Update Microsoft.Data.SqlClient.csproj --- .../netfx/src/Microsoft.Data.SqlClient.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index d6f95e6910..df8e73b2d3 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -338,7 +338,6 @@ Microsoft\Data\SqlClient\SqlCommandBuilder.cs - Component Microsoft\Data\SqlClient\SqlCommandSet.cs From 5fcaab32596d6262ab8c31ea3bd351e0e2ad6547 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Thu, 2 Dec 2021 11:04:26 -0800 Subject: [PATCH 09/25] rename simulator enclave provider --- .../src/Microsoft.Data.SqlClient.csproj | 7 +- .../netfx/src/Microsoft.Data.SqlClient.csproj | 6 +- .../SqlClient/SimulatorEnclaveProvider.cs | 114 ------------------ .../NoneAttestationEnclaveProvider.cs} | 27 ++--- 4 files changed, 16 insertions(+), 138 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs rename src/Microsoft.Data.SqlClient/{netcore/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.NetCoreApp.cs => src/Microsoft/Data/SqlClient/NoneAttestationEnclaveProvider.cs} (86%) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 5b808d9b78..d905ad16a9 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -488,6 +488,9 @@ Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProvider.cs + + Microsoft\Data\SqlClient\NoneAttestationEnclaveProvider.cs + Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProviderBase.cs @@ -507,9 +510,6 @@ - - - Resources\StringsHelper.NetCore.cs @@ -558,7 +558,6 @@ Microsoft\Data\SqlClient\SqlSequentialStream.cs - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index df8e73b2d3..44fa3e0f15 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -165,6 +165,9 @@ Microsoft\Data\SqlClient\AzureAttestationBasedEnclaveProvider.cs + + Microsoft\Data\SqlClient\NoneAttestationEnclaveProvider.cs + Microsoft\Data\SqlClient\EnclaveDelegate.cs @@ -629,9 +632,6 @@ - - - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs deleted file mode 100644 index 9a8550934c..0000000000 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.cs +++ /dev/null @@ -1,114 +0,0 @@ -// 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.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Runtime.Caching; -using System.Security.Cryptography; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Collections.Concurrent; - -namespace Microsoft.Data.SqlClient -{ - internal class SimulatorEnclaveProvider : EnclaveProviderBase - { - private static readonly int EnclaveSessionHandleSize = 8; - - // 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); - } - - // 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(384); - clientDHKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; - clientDHKey.HashAlgorithm = CngAlgorithm.Sha256; - - return new SqlEnclaveAttestationParameters(2, new byte[] { }, 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, ECDiffieHellman clientDHKey, EnclaveSessionParameters enclaveSessionParameters, 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(enclaveSessionParameters, out counter); - - if (sqlEnclaveSession == null) - { - if (!string.IsNullOrEmpty(enclaveSessionParameters.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)); - - 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); - } - else - { - throw new AlwaysEncryptedAttestationException(Strings.FailToCreateEnclaveSession); - } - } - } - finally - { - UpdateEnclaveSessionLockStatus(sqlEnclaveSession); - } - } - - /// - /// When overridden in a derived class, looks up and evicts an enclave session from the enclave session cache, if the provider implements session caching. - /// - /// The set of parameters required for enclave session. - /// The session to be invalidated. - internal override void InvalidateEnclaveSession(EnclaveSessionParameters enclaveSessionParameters, SqlEnclaveSession enclaveSessionToInvalidate) - { - InvalidateEnclaveSessionHelper(enclaveSessionParameters, enclaveSessionToInvalidate); - } - } -} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/NoneAttestationEnclaveProvider.cs similarity index 86% rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.NetCoreApp.cs rename to src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/NoneAttestationEnclaveProvider.cs index fdf6d67d54..269786db9a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SimulatorEnclaveProvider.NetCoreApp.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/NoneAttestationEnclaveProvider.cs @@ -3,21 +3,17 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Runtime.Caching; using System.Security.Cryptography; -using System.Text; using System.Threading; -using System.Threading.Tasks; -using System.Collections.Concurrent; namespace Microsoft.Data.SqlClient { - internal class SimulatorEnclaveProvider : EnclaveProviderBase + internal class NoneAttestationEnclaveProvider : EnclaveProviderBase { private static readonly int EnclaveSessionHandleSize = 8; + private const int DiffieHellmanKeySize = 384; + private const int NoneAttestationProtocolId = 2; // 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. @@ -29,18 +25,15 @@ internal override void GetEnclaveSession(EnclaveSessionParameters enclaveSession // 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) { - // The key derivation function and hash algorithm name are specified when key derivation is performed - ECDiffieHellman clientDHKey = ECDiffieHellman.Create(); - clientDHKey.KeySize = 384; - - return new SqlEnclaveAttestationParameters(2, new byte[] { }, clientDHKey); + ECDiffieHellman clientDHKey = KeyConverter.CreateECDiffieHellman(DiffieHellmanKeySize); + return new SqlEnclaveAttestationParameters(NoneAttestationProtocolId, new byte[] { }, 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. + // 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 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) + // 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; @@ -53,14 +46,14 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell { if (!string.IsNullOrEmpty(enclaveSessionParameters.AttestationUrl)) { - ////Read AttestationInfo + // 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 + // read secure session info uint sizeOfSecureSessionInfoResponse = BitConverter.ToUInt32(attestationInfo, attestationInfoOffset); attestationInfoOffset += sizeof(UInt32); From a39aa8827db80b3c8b27b338f30d9d1eec1903f7 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Thu, 2 Dec 2021 11:10:51 -0800 Subject: [PATCH 10/25] Update EnclaveDelegate.Crypto.cs --- .../src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs index 241c6aaf58..fbc2b50523 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs @@ -103,8 +103,8 @@ private SqlColumnEncryptionEnclaveProvider GetEnclaveProvider(SqlConnectionAttes #if ENCLAVE_SIMULATOR case SqlConnectionAttestationProtocol.SIM: - SimulatorEnclaveProvider simulatorEnclaveProvider = new SimulatorEnclaveProvider(); - s_enclaveProviders[attestationProtocol] = (SqlColumnEncryptionEnclaveProvider)simulatorEnclaveProvider; + NoneAttestationEnclaveProvider noneAttestationEnclaveProvider = new NoneAttestationEnclaveProvider(); + s_enclaveProviders[attestationProtocol] = (SqlColumnEncryptionEnclaveProvider)noneAttestationEnclaveProvider; sqlColumnEncryptionEnclaveProvider = s_enclaveProviders[attestationProtocol]; break; #endif From 7d95c363f06f3927701b85d044715dd950d5f252 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Thu, 2 Dec 2021 14:13:40 -0800 Subject: [PATCH 11/25] Update EnclaveDelegate.Crypto.cs --- .../src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs index fbc2b50523..e75c1fccd0 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs @@ -101,13 +101,11 @@ private SqlColumnEncryptionEnclaveProvider GetEnclaveProvider(SqlConnectionAttes sqlColumnEncryptionEnclaveProvider = s_enclaveProviders[attestationProtocol]; break; -#if ENCLAVE_SIMULATOR - case SqlConnectionAttestationProtocol.SIM: + case SqlConnectionAttestationProtocol.None: NoneAttestationEnclaveProvider noneAttestationEnclaveProvider = new NoneAttestationEnclaveProvider(); - s_enclaveProviders[attestationProtocol] = (SqlColumnEncryptionEnclaveProvider)noneAttestationEnclaveProvider; + s_enclaveProviders[attestationProtocol] = noneAttestationEnclaveProvider; sqlColumnEncryptionEnclaveProvider = s_enclaveProviders[attestationProtocol]; break; -#endif default: break; From a4d148a7e6b60ee24c27a3245b88e98c2fdd81d3 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Thu, 2 Dec 2021 14:15:43 -0800 Subject: [PATCH 12/25] use Array.Empty() --- .../Microsoft/Data/SqlClient/NoneAttestationEnclaveProvider.cs | 2 +- .../Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/NoneAttestationEnclaveProvider.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/NoneAttestationEnclaveProvider.cs index 269786db9a..ff36d1604c 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/NoneAttestationEnclaveProvider.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/NoneAttestationEnclaveProvider.cs @@ -26,7 +26,7 @@ internal override void GetEnclaveSession(EnclaveSessionParameters enclaveSession internal override SqlEnclaveAttestationParameters GetAttestationParameters(string attestationUrl, byte[] customData, int customDataLength) { ECDiffieHellman clientDHKey = KeyConverter.CreateECDiffieHellman(DiffieHellmanKeySize); - return new SqlEnclaveAttestationParameters(NoneAttestationProtocolId, new byte[] { }, clientDHKey); + return new SqlEnclaveAttestationParameters(NoneAttestationProtocolId, Array.Empty(), clientDHKey); } // 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. diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs index f71047d965..4920e3f528 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs @@ -95,7 +95,7 @@ internal override void GetEnclaveSession(EnclaveSessionParameters enclaveSession internal override SqlEnclaveAttestationParameters GetAttestationParameters(string attestationUrl, byte[] customData, int customDataLength) { ECDiffieHellman clientDHKey = KeyConverter.CreateECDiffieHellman(DiffieHellmanKeySize); - return new SqlEnclaveAttestationParameters(VsmHGSProtocolId, new byte[] { }, clientDHKey); + return new SqlEnclaveAttestationParameters(VsmHGSProtocolId, Array.Empty(), 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. From 0be73d551e7bbf9cf1fd775600486c532bbf5641 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Thu, 2 Dec 2021 14:27:31 -0800 Subject: [PATCH 13/25] docs --- doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml | 2 +- .../SqlConnectionAttestationProtocol.xml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml index ae9ed935b5..96a78643c8 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml @@ -527,7 +527,7 @@ End Module |Application Intent

-or-

ApplicationIntent|ReadWrite|Declares the application workload type when connecting to a server. Possible values are `ReadOnly` and `ReadWrite`. For example:

`ApplicationIntent=ReadOnly`

For more information about SqlClient support for Always On Availability Groups, see [SqlClient Support for High Availability, Disaster Recovery](/sql/connect/ado-net/sql/sqlclient-support-high-availability-disaster-recovery).| |Application Name|N/A|The name of the application. If no application name is provided, 'Framework Microsoft SqlClient Data Provider' when running on .NET Framework and 'Core Microsoft SqlClient Data Provider' otherwise.

An application name can be 128 characters or less.| |AttachDBFilename

-or-

Extended Properties

-or-

Initial File Name|N/A|The name of the primary database file, including the full path name of an attachable database. AttachDBFilename is only supported for primary data files with an .mdf extension.

If the value of the AttachDBFileName key is specified in the connection string, the database is attached and becomes the default database for the connection.

If this key is not specified and if the database was previously attached, the database will not be reattached. The previously attached database will be used as the default database for the connection.

If this key is specified together with the AttachDBFileName key, the value of this key will be used as the alias. However, if the name is already used in another attached database, the connection will fail.

The path may be absolute or relative by using the DataDirectory substitution string. If DataDirectory is used, the database file must exist within a subdirectory of the directory pointed to by the substitution string. **Note:** Remote server, HTTP, and UNC path names are not supported.

The database name must be specified with the keyword 'database' (or one of its aliases) as in the following:

"AttachDbFileName=|DataDirectory|\data\YourDB.mdf;integrated security=true;database=YourDatabase"

An error will be generated if a log file exists in the same directory as the data file and the 'database' keyword is used when attaching the primary data file. In this case, remove the log file. Once the database is attached, a new log file will be automatically generated based on the physical path.| -|Attestation Protocol|N/A|Gets or sets the value of Attestation Protocol.

Valid values are:
`AAS`
`HGS`| +|Attestation Protocol|N/A|Gets or sets the value of Attestation Protocol.

Valid values are:
`AAS`
`HGS`
`None`| |Authentication|N/A|The authentication method used for [Connecting to SQL Database By Using Azure Active Directory Authentication](https://azure.microsoft.com/documentation/articles/sql-database-aad-authentication/#7-connect-to-your-database-by-using-azure-active-directory-identities).

Valid values are:

`Active Directory Integrated`, `Active Directory Interactive`, `Active Directory Password`, `Active Directory Service Principal`, `Active Directory Device Code Flow`, `Active Directory Managed Identity`, `Active Directory MSI`, `Active Directory Default`, `Sql Password`.| |Column Encryption Setting|disabled|Enables or disables [Always Encrypted](/sql/relational-databases/security/encryption/always-encrypted-database-engine) functionality for the connection. Supported values are: `enabled` and `disabled`| |Command Timeout|30|The default wait time (in seconds) before terminating the attempt to execute a command and generating an error.

Valid values are greater than or equal to 0 and less than or equal to 2147483647.| diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionAttestationProtocol.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionAttestationProtocol.xml index d5f32ef2d3..db98ad4fdf 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionAttestationProtocol.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionAttestationProtocol.xml @@ -13,10 +13,10 @@ Attestation portocol for Azure Attestation Service 1 - - Attestation protocol for Simulator + + Attestation protocol for no attestation. Only compatible with Virtualization-based security (VBS) enclaves. An Enclave Attestation Url is not required when using this protocol. 2 - + Attestation protocol for Host Guardian Service 3 From b4fc1904ae8d787cc9f29751ce34fb2199da5b96 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Fri, 3 Dec 2021 09:54:53 -0800 Subject: [PATCH 14/25] use enum for protocol id fields --- .../Data/SqlClient/AzureAttestationBasedEnclaveProvider.cs | 2 +- .../Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/AzureAttestationBasedEnclaveProvider.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/AzureAttestationBasedEnclaveProvider.cs index d08db25036..0e891924fb 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/AzureAttestationBasedEnclaveProvider.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/AzureAttestationBasedEnclaveProvider.cs @@ -49,7 +49,7 @@ internal class AzureAttestationEnclaveProvider : EnclaveProviderBase { #region Constants private const int DiffieHellmanKeySize = 384; - private const int AzureBasedAttestationProtocolId = 1; + private const int AzureBasedAttestationProtocolId = (int)SqlConnectionAttestationProtocol.AAS; private const int SigningKeyRetryInSec = 3; #endregion diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs index 4920e3f528..6c940e3749 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs @@ -22,7 +22,7 @@ internal abstract class VirtualizationBasedSecurityEnclaveProviderBase : Enclave #region Constants private const int DiffieHellmanKeySize = 384; - private const int VsmHGSProtocolId = 3; + private const int VsmHGSProtocolId = (int)SqlConnectionAttestationProtocol.HGS; // ENCLAVE_IDENTITY related constants private static readonly EnclaveIdentity ExpectedPolicy = new EnclaveIdentity() From d0e204d104f479af3887bf7f43c99028244bbe77 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Fri, 3 Dec 2021 11:25:24 -0800 Subject: [PATCH 15/25] netcore --- .../netcore/ref/Microsoft.Data.SqlClient.cs | 6 +- .../Microsoft/Data/SqlClient/SqlCommand.cs | 10 ++- .../src/Microsoft/Data/SqlClient/TdsEnums.cs | 6 +- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 20 +++--- .../src/Microsoft/Data/SqlClient/TdsEnums.cs | 6 +- .../Data/Common/DbConnectionStringCommon.cs | 19 ++---- .../Data/SqlClient/EnclaveDelegate.Crypto.cs | 4 +- .../NoneAttestationEnclaveProvider.cs | 66 +++++++++---------- 8 files changed, 59 insertions(+), 78 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs index 22cbb29f6e..3d63a3f9db 100644 --- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs +++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs @@ -472,10 +472,8 @@ public enum SqlConnectionAttestationProtocol /// AAS = 1, -#if ENCLAVE_SIMULATOR - /// - SIM = 2, -#endif + /// + None = 2, /// HGS = 3 diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs index 85fe6156ab..508dff174b 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -206,7 +206,8 @@ internal bool IsColumnEncryptionEnabled internal bool ShouldUseEnclaveBasedWorkflow { - get { return !string.IsNullOrWhiteSpace(_activeConnection.EnclaveAttestationUrl) && IsColumnEncryptionEnabled; } + get { return (!string.IsNullOrWhiteSpace(_activeConnection.EnclaveAttestationUrl) || Connection.AttestationProtocol == SqlConnectionAttestationProtocol.None) && + IsColumnEncryptionEnabled; } } /// @@ -4211,7 +4212,7 @@ private void ReadDescribeEncryptionParameterResults(SqlDataReader ds, ReadOnlyDi if (isRequestedByEnclave) { - if (string.IsNullOrWhiteSpace(this.Connection.EnclaveAttestationUrl)) + if (string.IsNullOrWhiteSpace(this.Connection.EnclaveAttestationUrl) && Connection.AttestationProtocol != SqlConnectionAttestationProtocol.None) { throw SQL.NoAttestationUrlSpecifiedForEnclaveBasedQuerySpDescribe(this._activeConnection.Parser.EnclaveType); } @@ -4636,8 +4637,11 @@ private void GenerateEnclavePackage() return; } - if (string.IsNullOrWhiteSpace(this._activeConnection.EnclaveAttestationUrl)) + if (string.IsNullOrWhiteSpace(this._activeConnection.EnclaveAttestationUrl) && + Connection.AttestationProtocol != SqlConnectionAttestationProtocol.None) + { throw SQL.NoAttestationUrlSpecifiedForEnclaveBasedQueryGeneratingEnclavePackage(this._activeConnection.Parser.EnclaveType); + } string enclaveType = this._activeConnection.Parser.EnclaveType; if (string.IsNullOrWhiteSpace(enclaveType)) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsEnums.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsEnums.cs index 728e521847..fd4f4313e6 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsEnums.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsEnums.cs @@ -1070,10 +1070,8 @@ public enum SqlConnectionAttestationProtocol /// AAS = 1, -#if ENCLAVE_SIMULATOR - /// - SIM = 2, -#endif + /// + None = 2, /// HGS = 3 diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 44be90bb31..d38969f593 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -3184,7 +3184,7 @@ private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) } // Check if enclave attestation url was specified and server does not return an enclave type and we aren't going to be routed to another server. - if (!string.IsNullOrWhiteSpace(_connHandler.ConnectionOptions.EnclaveAttestationUrl)) + if (!string.IsNullOrWhiteSpace(_connHandler.ConnectionOptions.EnclaveAttestationUrl) || attestationProtocol == SqlConnectionAttestationProtocol.None) { if (string.IsNullOrWhiteSpace(EnclaveType)) { @@ -3193,7 +3193,7 @@ private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) else { // Check if the attestation protocol is specified and supports the enclave type. - if (SqlConnectionAttestationProtocol.NotSpecified != attestationProtocol && !IsValidAttestationProtocol(attestationProtocol, EnclaveType)) + if (attestationProtocol != SqlConnectionAttestationProtocol.NotSpecified && !IsValidAttestationProtocol(attestationProtocol, EnclaveType)) { throw SQL.AttestationProtocolNotSupportEnclaveType(ConvertAttestationProtocolToString(attestationProtocol), EnclaveType); } @@ -3210,10 +3210,8 @@ private bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol attesta { case TdsEnums.ENCLAVE_TYPE_VBS: if (attestationProtocol != SqlConnectionAttestationProtocol.AAS -#if ENCLAVE_SIMULATOR - && attestationProtocol != SqlConnectionAttestationProtocol.SIM -#endif - && attestationProtocol != SqlConnectionAttestationProtocol.HGS) + && attestationProtocol != SqlConnectionAttestationProtocol.HGS + && attestationProtocol != SqlConnectionAttestationProtocol.None) { return false; } @@ -3222,7 +3220,7 @@ private bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol attesta case TdsEnums.ENCLAVE_TYPE_SGX: #if ENCLAVE_SIMULATOR if (attestationProtocol != SqlConnectionAttestationProtocol.AAS - && attestationProtocol != SqlConnectionAttestationProtocol.SIM) + && attestationProtocol != SqlConnectionAttestationProtocol.None) #else if (attestationProtocol != SqlConnectionAttestationProtocol.AAS) #endif @@ -3233,7 +3231,7 @@ private bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol attesta #if ENCLAVE_SIMULATOR case TdsEnums.ENCLAVE_TYPE_SIMULATOR: - if (attestationProtocol != SqlConnectionAttestationProtocol.SIM) + if (attestationProtocol != SqlConnectionAttestationProtocol.None) { return false; } @@ -3257,10 +3255,8 @@ private string ConvertAttestationProtocolToString(SqlConnectionAttestationProtoc case SqlConnectionAttestationProtocol.HGS: return "HGS"; -#if ENCLAVE_SIMULATOR - case SqlConnectionAttestationProtocol.SIM: - return "SIM"; -#endif + case SqlConnectionAttestationProtocol.None: + return "None"; default: return "NotSpecified"; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsEnums.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsEnums.cs index 20a7fad79e..9ec2f3b4b7 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsEnums.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsEnums.cs @@ -1069,10 +1069,8 @@ public enum SqlConnectionAttestationProtocol /// AAS = 1, -#if ENCLAVE_SIMULATOR - /// - SIM = 2, -#endif + /// + None = 2, /// HGS = 3 diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs index aad002c116..0557ebaa75 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs @@ -715,13 +715,11 @@ internal static bool TryConvertToAttestationProtocol(string value, out SqlConnec result = SqlConnectionAttestationProtocol.AAS; return true; } -#if ENCLAVE_SIMULATOR - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionAttestationProtocol.SIM))) + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionAttestationProtocol.None))) { - result = SqlConnectionAttestationProtocol.SIM; + result = SqlConnectionAttestationProtocol.None; return true; } -#endif else { result = DbConnectionStringDefaults.AttestationProtocol; @@ -731,18 +729,11 @@ internal static bool TryConvertToAttestationProtocol(string value, out SqlConnec internal static bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol value) { -#if ENCLAVE_SIMULATOR Debug.Assert(Enum.GetNames(typeof(SqlConnectionAttestationProtocol)).Length == 4, "SqlConnectionAttestationProtocol enum has changed, update needed"); return value == SqlConnectionAttestationProtocol.NotSpecified || value == SqlConnectionAttestationProtocol.HGS || value == SqlConnectionAttestationProtocol.AAS - || value == SqlConnectionAttestationProtocol.SIM; -#else - Debug.Assert(Enum.GetNames(typeof(SqlConnectionAttestationProtocol)).Length == 3, "SqlConnectionAttestationProtocol enum has changed, update needed"); - return value == SqlConnectionAttestationProtocol.NotSpecified - || value == SqlConnectionAttestationProtocol.HGS - || value == SqlConnectionAttestationProtocol.AAS; -#endif + || value == SqlConnectionAttestationProtocol.None; } internal static string AttestationProtocolToString(SqlConnectionAttestationProtocol value) @@ -753,9 +744,7 @@ internal static string AttestationProtocolToString(SqlConnectionAttestationProto { SqlConnectionAttestationProtocol.AAS => nameof(SqlConnectionAttestationProtocol.AAS), SqlConnectionAttestationProtocol.HGS => nameof(SqlConnectionAttestationProtocol.HGS), -#if ENCLAVE_SIMULATOR - SqlConnectionAttestationProtocol.SIM => nameof(SqlConnectionAttestationProtocol.SIM), -#endif + SqlConnectionAttestationProtocol.None => nameof(SqlConnectionAttestationProtocol.None), _ => null }; } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs index e75c1fccd0..03adc78d6d 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs @@ -218,8 +218,8 @@ private string ConvertAttestationProtocolToString(SqlConnectionAttestationProtoc return "HGS"; #if ENCLAVE_SIMULATOR - case SqlConnectionAttestationProtocol.SIM: - return "SIM"; + case SqlConnectionAttestationProtocol.None: + return "None"; #endif default: diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/NoneAttestationEnclaveProvider.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/NoneAttestationEnclaveProvider.cs index ff36d1604c..05629f3036 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/NoneAttestationEnclaveProvider.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/NoneAttestationEnclaveProvider.cs @@ -13,7 +13,7 @@ internal class NoneAttestationEnclaveProvider : EnclaveProviderBase { private static readonly int EnclaveSessionHandleSize = 8; private const int DiffieHellmanKeySize = 384; - private const int NoneAttestationProtocolId = 2; + private const int NoneAttestationProtocolId = (int)SqlConnectionAttestationProtocol.None; // 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. @@ -44,45 +44,43 @@ internal override void CreateEnclaveSession(byte[] attestationInfo, ECDiffieHell if (sqlEnclaveSession == null) { - if (!string.IsNullOrEmpty(enclaveSessionParameters.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 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); + // 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; + 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); + 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[] 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[] 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); - } - else + 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 new AlwaysEncryptedAttestationException(Strings.FailToCreateEnclaveSession); } From 7860792db4999e7910cb59d72be7e3a78f67eb0c Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Tue, 7 Dec 2021 11:15:55 -0800 Subject: [PATCH 16/25] tests --- .../ConnectionStringBuilderShould.cs | 31 +++++++++++++++++-- .../ManualTests/AlwaysEncrypted/ApiShould.cs | 18 +++++++++++ .../TestFixtures/SQLSetupStrategy.cs | 1 + .../ManualTests/DataCommon/DataTestUtility.cs | 13 ++++++++ .../SQL/ExceptionTest/ExceptionTest.cs | 7 +++++ .../SqlDbManager.cs | 20 +++++++++--- .../Config.cs | 1 + .../config.default.json | 1 + 8 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs index 5c9c124763..d7483a5e76 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs @@ -88,6 +88,17 @@ public void TestSqlConnectionStringAttestationProtocol() Assert.Equal(SqlConnectionAttestationProtocol.NotSpecified, connectionStringBuilder3.AttestationProtocol); Assert.True(string.IsNullOrEmpty(connectionStringBuilder3.DataSource)); + + SqlConnectionStringBuilder connectionStringBuilder4 = new SqlConnectionStringBuilder(); + connectionStringBuilder4.AttestationProtocol = SqlConnectionAttestationProtocol.None; + Assert.Equal(SqlConnectionAttestationProtocol.None, connectionStringBuilder4.AttestationProtocol); + connectionStringBuilder4.DataSource = @"localhost"; + + VerifyAttestationProtocol(connectionStringBuilder4, SqlConnectionAttestationProtocol.None); + + connectionStringBuilder4.Clear(); + Assert.Equal(SqlConnectionAttestationProtocol.NotSpecified, connectionStringBuilder4.AttestationProtocol); + Assert.True(string.IsNullOrEmpty(connectionStringBuilder4.DataSource)); } [Fact] @@ -117,20 +128,28 @@ public void TestSqlConnectionStringBuilderEquivilantTo_AttestationProtocol() { SqlConnectionAttestationProtocol protocol1 = SqlConnectionAttestationProtocol.AAS; SqlConnectionAttestationProtocol protocol2 = SqlConnectionAttestationProtocol.HGS; + SqlConnectionAttestationProtocol protocol3 = SqlConnectionAttestationProtocol.None; SqlConnectionStringBuilder connectionStringBuilder1 = new SqlConnectionStringBuilder(); SqlConnectionStringBuilder connectionStringBuilder2 = new SqlConnectionStringBuilder(); + SqlConnectionStringBuilder connectionStringBuilder3 = new SqlConnectionStringBuilder(); // Modify the default value and set the same value on the both the builder objects above. connectionStringBuilder1.AttestationProtocol = protocol1; connectionStringBuilder2.AttestationProtocol = protocol1; + connectionStringBuilder3.AttestationProtocol = protocol1; // Use the EquivalentTo function to compare both the builder objects and make sure the result is expected. Assert.True(connectionStringBuilder1.EquivalentTo(connectionStringBuilder2)); + Assert.True(connectionStringBuilder1.EquivalentTo(connectionStringBuilder3)); connectionStringBuilder2.AttestationProtocol = protocol2; - Assert.True(!connectionStringBuilder1.EquivalentTo(connectionStringBuilder2)); + Assert.True(!connectionStringBuilder3.EquivalentTo(connectionStringBuilder2)); + + connectionStringBuilder3.AttestationProtocol = protocol3; + Assert.True(!connectionStringBuilder1.EquivalentTo(connectionStringBuilder3)); + Assert.True(!connectionStringBuilder2.EquivalentTo(connectionStringBuilder3)); } @@ -151,14 +170,15 @@ public void TestSqlConnectionStringBuilderColumnEncryptionSetting(SqlConnectionC [InlineData(SqlConnectionAttestationProtocol.AAS)] [InlineData(SqlConnectionAttestationProtocol.HGS)] [InlineData(SqlConnectionAttestationProtocol.NotSpecified)] + [InlineData(SqlConnectionAttestationProtocol.None)] public void TestSqlConnectionStringBuilderAttestationProtocol(SqlConnectionAttestationProtocol protocol) { SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder(); connectionStringBuilder.DataSource = @"localhost"; // Modify value. - connectionStringBuilder.AttestationProtocol = protocol; - + connectionStringBuilder.AttestationProtocol = protocol; + //Create a connection object with the above builder and verify the expected value. VerifyAttestationProtocol(connectionStringBuilder, protocol); } @@ -313,6 +333,11 @@ public void TestSqlConnectionStringBuilderTryGetValue(SqlConnectionColumnEncrypt tryGetValueResult = connectionStringBuilder.TryGetValue(@"Attestation Protocol", out outputValue); Assert.True(tryGetValueResult); Assert.Equal(SqlConnectionAttestationProtocol.AAS, outputValue); + + connectionStringBuilder.AttestationProtocol = SqlConnectionAttestationProtocol.None; + + Assert.True(connectionStringBuilder.TryGetValue(@"Attestation Protocol", out outputValue)); + Assert.Equal(SqlConnectionAttestationProtocol.None, outputValue); } [Theory] diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs index 2bec916210..5f60faddb5 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs @@ -2122,6 +2122,24 @@ public void TestSqlCommandCancellationToken(string connection, int initalValue, } } + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsSGXEnclaveConnStringSetup))] + public void TestNoneAttestationProtocolWithSGXEnclave() + { + SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionStringAASSGX); + builder.AttestationProtocol = SqlConnectionAttestationProtocol.None; + builder.EnclaveAttestationUrl = string.Empty; + + using (SqlConnection connection = new(builder.ConnectionString)) + { + InvalidOperationException ex = Assert.Throws(() => connection.Open()); + string expectedErrorMessage = string.Format( + SystemDataResourceManager.Instance.TCE_AttestationProtocolNotSupportEnclaveType, + SqlConnectionAttestationProtocol.None.ToString(), "SGX"); + Assert.Contains(expectedErrorMessage, ex.Message); + } + } + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringSetupForAE))] [ClassData(typeof(AEConnectionStringProvider))] public void TestConnectionCustomKeyStoreProviderDuringAeQuery(string connectionString) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs index 3a995dd9f8..0cd8436cb4 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs @@ -137,6 +137,7 @@ protected List CreateTables(IList columnEncryptionKe SqlNullValuesTable = new SqlNullValuesTable(GenerateUniqueName("SqlNullValuesTable"), columnEncryptionKeys[0]); tables.Add(SqlNullValuesTable); + // columnEncryptionKeys[2] is encrypted with DummyCMK. use this encrypted column to test custom key store providers CustomKeyStoreProviderTestTable = new ApiTestTable(GenerateUniqueName("CustomKeyStoreProviderTestTable"), columnEncryptionKeys[2], columnEncryptionKeys[0], useDeterministicEncryption: true); tables.Add(CustomKeyStoreProviderTestTable); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 27acea362d..d13d20638a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -27,6 +27,7 @@ public static class DataTestUtility public static readonly string TCPConnectionString = null; public static readonly string TCPConnectionStringHGSVBS = null; public static readonly string TCPConnectionStringAASVBS = null; + public static readonly string TCPConnectionStringNoneVBS = null; public static readonly string TCPConnectionStringAASSGX = null; public static readonly string AADAuthorityURL = null; public static readonly string AADPasswordConnectionString = null; @@ -86,6 +87,7 @@ static DataTestUtility() TCPConnectionString = c.TCPConnectionString; TCPConnectionStringHGSVBS = c.TCPConnectionStringHGSVBS; TCPConnectionStringAASVBS = c.TCPConnectionStringAASVBS; + TCPConnectionStringNoneVBS = c.TCPConnectionStringNoneVBS; TCPConnectionStringAASSGX = c.TCPConnectionStringAASSGX; AADAuthorityURL = c.AADAuthorityURL; AADPasswordConnectionString = c.AADPasswordConnectionString; @@ -148,6 +150,12 @@ static DataTestUtility() AEConnStrings.Add(TCPConnectionStringAASVBS); } + if (!string.IsNullOrEmpty(TCPConnectionStringNoneVBS)) + { + AEConnStrings.Add(TCPConnectionStringNoneVBS); + AEConnStringsSetup.Add(TCPConnectionStringNoneVBS); + } + if (!string.IsNullOrEmpty(TCPConnectionStringAASSGX)) { AEConnStrings.Add(TCPConnectionStringAASSGX); @@ -296,6 +304,11 @@ public static bool AreConnStringSetupForAE() return AEConnStrings.Count > 0 && IsNotAzureSynapse(); } + public static bool IsSGXEnclaveConnStringSetup() + { + return !string.IsNullOrEmpty(TCPConnectionStringAASSGX); + } + public static bool IsAADPasswordConnStrSetup() { return !string.IsNullOrEmpty(AADPasswordConnectionString); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs index a52dee1ad4..9ddeaad727 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs @@ -5,6 +5,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Data; using System.Globalization; using System.Threading.Tasks; using Xunit; @@ -251,6 +252,7 @@ public static void EnclavesConnectionExceptionTest() string connectionStringWithAttestationProtocol = DataTestUtility.TCPConnectionString + ";Attestation Protocol = HGS;"; string connectionStringWithAttestationURL = DataTestUtility.TCPConnectionString + ";Enclave Attestation URL = https://dummyURL;"; string connectionStringWithEnclave = connectionStringWithAttestationURL + ";Attestation Protocol = HGS;"; + string connectionStringWithNoneAttestationProtocol = DataTestUtility.TCPConnectionString + ";Attestation Protocol = None;"; InvalidOperationException e1 = Assert.Throws(() => new SqlConnection(connectionStringWithAttestationURL).Open()); Assert.Contains("You have specified the enclave attestation URL in the connection string", e1.Message); @@ -260,6 +262,11 @@ public static void EnclavesConnectionExceptionTest() InvalidOperationException e3 = Assert.Throws(() => new SqlConnection(connectionStringWithEnclave).Open()); Assert.Contains("You have specified the enclave attestation URL and attestation protocol in the connection string", e3.Message); + + // connection should work if attestation protocol is None but no attestation url is provided + SqlConnection sqlConnection = new(connectionStringWithNoneAttestationProtocol); + sqlConnection.Open(); + Assert.True(sqlConnection.State is ConnectionState.Open); } [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs index a09c9313a8..602383f160 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs @@ -25,6 +25,7 @@ public static class SqlDbManager private const string NPConnectionString = "NPConnectionString"; private const string TCPConnectionStringAASSGX = "TCPConnectionStringAASSGX"; private const string TCPConnectionStringAASVBS = "TCPConnectionStringAASVBS"; + private const string TCPConnectionStringNoneVBS = "TCPConnectionStringNoneVBS"; private const string TCPConnectionStringHGSVBS = "TCPConnectionStringHGSVBS"; /// @@ -60,9 +61,11 @@ public static void Run(string[] args) if (args[0] == "CreateDatabase") { - // We do not create database for HGS-VBS since SQL Server for AASVBS and HGSVBS connection strings is same. + // We do not create database for HGS-VBS since SQL Server for AASVBS, HGSVBS and NoneVBS connection strings is same. // Do not create database for NP connection string, since server is always same as TCP - if (activeConnString.Key != TCPConnectionStringHGSVBS && activeConnString.Key != NPConnectionString) + if (activeConnString.Key != TCPConnectionStringHGSVBS && + activeConnString.Key != TCPConnectionStringNoneVBS && + activeConnString.Key != NPConnectionString) { //Create a new database CreateDatabase(dbName, context); @@ -74,9 +77,11 @@ public static void Run(string[] args) } else if (args[0] == "DropDatabase") { - // We do not drop database for HGS-VBS since SQL Server for AASVBS and HGSVBS connection strings is same. + // We do not drop database for HGS-VBS since SQL Server for AASVBS, HGSVBS and NoneVBS connection strings is same. // Do not drop database for NP connection string, since server is always same as TCP - if (activeConnString.Key != TCPConnectionStringHGSVBS && activeConnString.Key != NPConnectionString) + if (activeConnString.Key != TCPConnectionStringHGSVBS && + activeConnString.Key != TCPConnectionStringNoneVBS && + activeConnString.Key != NPConnectionString) { // Drop Northwind for test run. DropIfExistsDatabase(dbName, context); @@ -131,6 +136,10 @@ private static void LoadActiveConnectionStrings() { s_activeConnectionStrings.Add(TCPConnectionStringHGSVBS, s_configJson.TCPConnectionStringHGSVBS); } + if (!string.IsNullOrEmpty(s_configJson.TCPConnectionStringNoneVBS)) + { + s_activeConnectionStrings.Add(TCPConnectionStringNoneVBS, s_configJson.TCPConnectionStringNoneVBS); + } } } @@ -153,6 +162,9 @@ private static void UpdateConfig(string key, SqlConnectionStringBuilder builder) case TCPConnectionStringHGSVBS: s_configJson.TCPConnectionStringHGSVBS = builder.ConnectionString; break; + case TCPConnectionStringNoneVBS: + s_configJson.TCPConnectionStringNoneVBS = builder.ConnectionString; + break; } } diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs index dec84eabd1..101b0c0606 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs @@ -14,6 +14,7 @@ public class Config public string NPConnectionString = null; public string TCPConnectionStringHGSVBS = null; public string TCPConnectionStringAASVBS = null; + public string TCPConnectionStringNoneVBS = null; public string TCPConnectionStringAASSGX = null; public string AADAuthorityURL = null; public string AADPasswordConnectionString = null; diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json index 043b73c4c9..c3210756bb 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json @@ -3,6 +3,7 @@ "NPConnectionString": "Data Source=np:localhost;Database=Northwind;Integrated Security=true;", "TCPConnectionStringHGSVBS": "", "TCPConnectionStringAASVBS": "", + "TCPConnectionStringNoneVBS": "", "TCPConnectionStringAASSGX": "", "EnclaveEnabled": false, "TracingEnabled": false, From 89e4932967fc0b2ddeeb8bf3452a891b133717c8 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Tue, 7 Dec 2021 13:08:10 -0800 Subject: [PATCH 17/25] Update SqlDbManager.cs --- .../SqlDbManager.cs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs index 602383f160..21678f481e 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs @@ -25,7 +25,6 @@ public static class SqlDbManager private const string NPConnectionString = "NPConnectionString"; private const string TCPConnectionStringAASSGX = "TCPConnectionStringAASSGX"; private const string TCPConnectionStringAASVBS = "TCPConnectionStringAASVBS"; - private const string TCPConnectionStringNoneVBS = "TCPConnectionStringNoneVBS"; private const string TCPConnectionStringHGSVBS = "TCPConnectionStringHGSVBS"; /// @@ -61,10 +60,9 @@ public static void Run(string[] args) if (args[0] == "CreateDatabase") { - // We do not create database for HGS-VBS since SQL Server for AASVBS, HGSVBS and NoneVBS connection strings is same. + // We do not create database for HGS-VBS since SQL Server for AASVBS and HGSVBS connection strings is same. // Do not create database for NP connection string, since server is always same as TCP - if (activeConnString.Key != TCPConnectionStringHGSVBS && - activeConnString.Key != TCPConnectionStringNoneVBS && + if (activeConnString.Key != TCPConnectionStringHGSVBS && activeConnString.Key != NPConnectionString) { //Create a new database @@ -77,10 +75,9 @@ public static void Run(string[] args) } else if (args[0] == "DropDatabase") { - // We do not drop database for HGS-VBS since SQL Server for AASVBS, HGSVBS and NoneVBS connection strings is same. + // We do not create database for HGS-VBS since SQL Server for AASVBS and HGSVBS connection strings is same. // Do not drop database for NP connection string, since server is always same as TCP if (activeConnString.Key != TCPConnectionStringHGSVBS && - activeConnString.Key != TCPConnectionStringNoneVBS && activeConnString.Key != NPConnectionString) { // Drop Northwind for test run. @@ -136,10 +133,6 @@ private static void LoadActiveConnectionStrings() { s_activeConnectionStrings.Add(TCPConnectionStringHGSVBS, s_configJson.TCPConnectionStringHGSVBS); } - if (!string.IsNullOrEmpty(s_configJson.TCPConnectionStringNoneVBS)) - { - s_activeConnectionStrings.Add(TCPConnectionStringNoneVBS, s_configJson.TCPConnectionStringNoneVBS); - } } } @@ -162,9 +155,6 @@ private static void UpdateConfig(string key, SqlConnectionStringBuilder builder) case TCPConnectionStringHGSVBS: s_configJson.TCPConnectionStringHGSVBS = builder.ConnectionString; break; - case TCPConnectionStringNoneVBS: - s_configJson.TCPConnectionStringNoneVBS = builder.ConnectionString; - break; } } From b91f0654adb0e023ae2821db148cd10de2d47bea Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Wed, 8 Dec 2021 10:44:39 -0800 Subject: [PATCH 18/25] netfx changes --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 6 ++-- .../netfx/ref/Microsoft.Data.SqlClient.cs | 6 ++-- .../Microsoft/Data/SqlClient/SqlCommand.cs | 13 +++++-- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 34 ++++++++----------- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index d38969f593..d4a5b65b79 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -3169,7 +3169,7 @@ private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) if (TceVersionSupported < TdsEnums.MIN_TCE_VERSION_WITH_ENCLAVE_SUPPORT) { // Check if enclave attestation url was specified and server does not support enclave computations and we aren't going to be routed to another server. - if (!string.IsNullOrWhiteSpace(_connHandler.ConnectionOptions.EnclaveAttestationUrl) && SqlConnectionAttestationProtocol.NotSpecified != attestationProtocol) + if (!string.IsNullOrWhiteSpace(_connHandler.ConnectionOptions.EnclaveAttestationUrl) && attestationProtocol != SqlConnectionAttestationProtocol.NotSpecified) { throw SQL.EnclaveComputationsNotSupported(); } @@ -3177,7 +3177,7 @@ private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) { throw SQL.AttestationURLNotSupported(); } - else if (SqlConnectionAttestationProtocol.NotSpecified != _connHandler.ConnectionOptions.AttestationProtocol) + else if (_connHandler.ConnectionOptions.AttestationProtocol != SqlConnectionAttestationProtocol.NotSpecified) { throw SQL.AttestationProtocolNotSupported(); } @@ -3193,7 +3193,7 @@ private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) else { // Check if the attestation protocol is specified and supports the enclave type. - if (attestationProtocol != SqlConnectionAttestationProtocol.NotSpecified && !IsValidAttestationProtocol(attestationProtocol, EnclaveType)) + if (SqlConnectionAttestationProtocol.NotSpecified != attestationProtocol && !IsValidAttestationProtocol(attestationProtocol, EnclaveType)) { throw SQL.AttestationProtocolNotSupportEnclaveType(ConvertAttestationProtocolToString(attestationProtocol), EnclaveType); } diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs index eca9091a58..6a6ae668e7 100644 --- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs +++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs @@ -889,10 +889,8 @@ public enum SqlConnectionAttestationProtocol /// AAS = 1, -#if ENCLAVE_SIMULATOR - /// - SIM = 2, -#endif + /// + None = 2, /// HGS = 3 diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs index 35f5353f89..d2a2b2c313 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -162,7 +162,11 @@ internal bool IsColumnEncryptionEnabled internal bool ShouldUseEnclaveBasedWorkflow { - get { return !string.IsNullOrWhiteSpace(_activeConnection.EnclaveAttestationUrl) && IsColumnEncryptionEnabled; } + get + { + return (!string.IsNullOrWhiteSpace(_activeConnection.EnclaveAttestationUrl) || Connection.AttestationProtocol == SqlConnectionAttestationProtocol.None) && + IsColumnEncryptionEnabled; + } } internal ConcurrentDictionary keysToBeSentToEnclave; @@ -4780,7 +4784,7 @@ private void ReadDescribeEncryptionParameterResults(SqlDataReader ds, ReadOnlyDi if (isRequestedByEnclave) { - if (string.IsNullOrWhiteSpace(this.Connection.EnclaveAttestationUrl)) + if (string.IsNullOrWhiteSpace(this.Connection.EnclaveAttestationUrl) && Connection.AttestationProtocol != SqlConnectionAttestationProtocol.None) { throw SQL.NoAttestationUrlSpecifiedForEnclaveBasedQuerySpDescribe(this._activeConnection.Parser.EnclaveType); } @@ -5244,8 +5248,11 @@ private void GenerateEnclavePackage() return; } - if (string.IsNullOrWhiteSpace(this._activeConnection.EnclaveAttestationUrl)) + if (string.IsNullOrWhiteSpace(this._activeConnection.EnclaveAttestationUrl) && + Connection.AttestationProtocol != SqlConnectionAttestationProtocol.None) + { throw SQL.NoAttestationUrlSpecifiedForEnclaveBasedQueryGeneratingEnclavePackage(this._activeConnection.Parser.EnclaveType); + } string enclaveType = this._activeConnection.Parser.EnclaveType; if (string.IsNullOrWhiteSpace(enclaveType)) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 56ff3c94c6..3c2febbe35 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -658,7 +658,7 @@ internal void Connect(ServerInfo serverInfo, // for DNS Caching phase 1 AssignPendingDNSInfo(serverInfo.UserProtocol, FQDNforDNSCahce); - if(!ClientOSEncryptionSupport) + if (!ClientOSEncryptionSupport) { //If encryption is required, an error will be thrown. if (encrypt) @@ -690,7 +690,7 @@ internal void Connect(ServerInfo serverInfo, // On Instance failure re-connect and flush SNI named instance cache. _physicalStateObj.SniContext = SniContext.Snix_Connect; - _physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, + _physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, _sniSpnBuffer, true, true, fParallel, transparentNetworkResolutionState, totalTimeout, _connHandler.ConnectionOptions.IPAddressPreference, serverInfo.ResolvedServerName); if (TdsEnums.SNI_SUCCESS != _physicalStateObj.Status) @@ -709,7 +709,7 @@ internal void Connect(ServerInfo serverInfo, AssignPendingDNSInfo(serverInfo.UserProtocol, FQDNforDNSCahce); SendPreLoginHandshake(instanceName, encrypt, !string.IsNullOrEmpty(certificate), useOriginalAddressInfo); - status = ConsumePreLoginHandshake(authType, encrypt, trustServerCert, integratedSecurity, serverCallback, clientCallback, + status = ConsumePreLoginHandshake(authType, encrypt, trustServerCert, integratedSecurity, serverCallback, clientCallback, out marsCapable, out _connHandler._fedAuthRequired); // Don't need to check for Sphinx failure, since we've already consumed @@ -3625,7 +3625,7 @@ private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) if (TceVersionSupported < TdsEnums.MIN_TCE_VERSION_WITH_ENCLAVE_SUPPORT) { // Check if enclave attestation url was specified and server does not support enclave computations and we aren't going to be routed to another server. - if (!string.IsNullOrWhiteSpace(_connHandler.ConnectionOptions.EnclaveAttestationUrl) && SqlConnectionAttestationProtocol.NotSpecified != attestationProtocol) + if (!string.IsNullOrWhiteSpace(_connHandler.ConnectionOptions.EnclaveAttestationUrl) && attestationProtocol != SqlConnectionAttestationProtocol.NotSpecified) { throw SQL.EnclaveComputationsNotSupported(); } @@ -3633,13 +3633,13 @@ private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) { throw SQL.AttestationURLNotSupported(); } - else if (SqlConnectionAttestationProtocol.NotSpecified != _connHandler.ConnectionOptions.AttestationProtocol) + else if (_connHandler.ConnectionOptions.AttestationProtocol != SqlConnectionAttestationProtocol.NotSpecified) { throw SQL.AttestationProtocolNotSupported(); } } // Check if enclave attestation url was specified and server does not return an enclave type and we aren't going to be routed to another server. - if (!string.IsNullOrWhiteSpace(_connHandler.ConnectionOptions.EnclaveAttestationUrl)) + if (!string.IsNullOrWhiteSpace(_connHandler.ConnectionOptions.EnclaveAttestationUrl) || attestationProtocol == SqlConnectionAttestationProtocol.None) { if (string.IsNullOrWhiteSpace(EnclaveType)) { @@ -3648,7 +3648,7 @@ private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) else { // Check if the attestation protocol is specified and supports the enclave type. - if (SqlConnectionAttestationProtocol.NotSpecified != attestationProtocol && !IsValidAttestationProtocol(attestationProtocol, EnclaveType)) + if (attestationProtocol != SqlConnectionAttestationProtocol.NotSpecified && !IsValidAttestationProtocol(attestationProtocol, EnclaveType)) { throw SQL.AttestationProtocolNotSupportEnclaveType(ConvertAttestationProtocolToString(attestationProtocol), EnclaveType); } @@ -3665,10 +3665,8 @@ private bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol attesta { case TdsEnums.ENCLAVE_TYPE_VBS: if (attestationProtocol != SqlConnectionAttestationProtocol.AAS -#if ENCLAVE_SIMULATOR - && attestationProtocol != SqlConnectionAttestationProtocol.SIM -#endif - && attestationProtocol != SqlConnectionAttestationProtocol.HGS) + && attestationProtocol != SqlConnectionAttestationProtocol.HGS + && attestationProtocol != SqlConnectionAttestationProtocol.None) { return false; } @@ -3677,7 +3675,7 @@ private bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol attesta case TdsEnums.ENCLAVE_TYPE_SGX: #if ENCLAVE_SIMULATOR if (attestationProtocol != SqlConnectionAttestationProtocol.AAS - && attestationProtocol != SqlConnectionAttestationProtocol.SIM) + && attestationProtocol != SqlConnectionAttestationProtocol.None) #else if (attestationProtocol != SqlConnectionAttestationProtocol.AAS) #endif @@ -3688,7 +3686,7 @@ private bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol attesta #if ENCLAVE_SIMULATOR case TdsEnums.ENCLAVE_TYPE_SIMULATOR: - if (attestationProtocol != SqlConnectionAttestationProtocol.SIM) + if (attestationProtocol != SqlConnectionAttestationProtocol.None) { return false; } @@ -3712,10 +3710,8 @@ private string ConvertAttestationProtocolToString(SqlConnectionAttestationProtoc case SqlConnectionAttestationProtocol.HGS: return "HGS"; -#if ENCLAVE_SIMULATOR - case SqlConnectionAttestationProtocol.SIM: - return "SIM"; -#endif + case SqlConnectionAttestationProtocol.None: + return "None"; default: return "NotSpecified"; @@ -6713,7 +6709,7 @@ internal bool TryReadSqlValue(SqlBuffer value, int length, TdsParserStateObject stateObj, SqlCommandColumnEncryptionSetting columnEncryptionOverride, - string columnName, + string columnName, SqlCommand command = null) { bool isPlp = md.metaType.IsPlp; @@ -10449,7 +10445,7 @@ internal Task TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, int timeout, boo if (releaseConnectionLock) { task.ContinueWith( - static (Task _, object state) => ((TdsParser)state)._connHandler._parserLock.Release(), + static (Task _, object state) => ((TdsParser)state)._connHandler._parserLock.Release(), state: this, scheduler: TaskScheduler.Default ); From b269df64fd948aaf3b1271c208f22afd1e04d5f1 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Wed, 8 Dec 2021 12:52:03 -0800 Subject: [PATCH 19/25] Update SqlDbManager.cs --- .../Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs index 21678f481e..a09c9313a8 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs @@ -62,8 +62,7 @@ public static void Run(string[] args) { // We do not create database for HGS-VBS since SQL Server for AASVBS and HGSVBS connection strings is same. // Do not create database for NP connection string, since server is always same as TCP - if (activeConnString.Key != TCPConnectionStringHGSVBS && - activeConnString.Key != NPConnectionString) + if (activeConnString.Key != TCPConnectionStringHGSVBS && activeConnString.Key != NPConnectionString) { //Create a new database CreateDatabase(dbName, context); @@ -75,10 +74,9 @@ public static void Run(string[] args) } else if (args[0] == "DropDatabase") { - // We do not create database for HGS-VBS since SQL Server for AASVBS and HGSVBS connection strings is same. + // We do not drop database for HGS-VBS since SQL Server for AASVBS and HGSVBS connection strings is same. // Do not drop database for NP connection string, since server is always same as TCP - if (activeConnString.Key != TCPConnectionStringHGSVBS && - activeConnString.Key != NPConnectionString) + if (activeConnString.Key != TCPConnectionStringHGSVBS && activeConnString.Key != NPConnectionString) { // Drop Northwind for test run. DropIfExistsDatabase(dbName, context); From 8ef2990aad0edcda07b045b00b1b2e5e297c9e91 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Wed, 8 Dec 2021 15:27:37 -0800 Subject: [PATCH 20/25] Update ExceptionTest.cs --- .../ManualTests/SQL/ExceptionTest/ExceptionTest.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs index 9ddeaad727..374751835d 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs @@ -263,10 +263,13 @@ public static void EnclavesConnectionExceptionTest() InvalidOperationException e3 = Assert.Throws(() => new SqlConnection(connectionStringWithEnclave).Open()); Assert.Contains("You have specified the enclave attestation URL and attestation protocol in the connection string", e3.Message); - // connection should work if attestation protocol is None but no attestation url is provided - SqlConnection sqlConnection = new(connectionStringWithNoneAttestationProtocol); - sqlConnection.Open(); - Assert.True(sqlConnection.State is ConnectionState.Open); + if (DataTestUtility.EnclaveEnabled) + { + // connection should work if attestation protocol is None but no attestation url is provided + SqlConnection sqlConnection = new(connectionStringWithNoneAttestationProtocol); + sqlConnection.Open(); + Assert.True(sqlConnection.State is ConnectionState.Open); + } } [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] From a46a7e7c66cedeb437cb466fefa4c4fe5d1c49bf Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Wed, 5 Jan 2022 11:05:34 -0800 Subject: [PATCH 21/25] Update src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs Co-authored-by: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> --- .../tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs index 374751835d..c9dfe33bda 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs @@ -268,7 +268,7 @@ public static void EnclavesConnectionExceptionTest() // connection should work if attestation protocol is None but no attestation url is provided SqlConnection sqlConnection = new(connectionStringWithNoneAttestationProtocol); sqlConnection.Open(); - Assert.True(sqlConnection.State is ConnectionState.Open); + Assert.Equal(ConnectionState.Open, sqlConnection.State); } } From 806eca74f443e165c14c3de4a5aff8d2e4dc9d66 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Wed, 19 Jan 2022 13:11:22 -0800 Subject: [PATCH 22/25] address feedback --- .../Microsoft/Data/SqlClient/SqlCommand.cs | 8 +++---- .../Microsoft/Data/SqlClient/SqlCommand.cs | 9 ++------ .../Data/SqlClient/EnclaveDelegate.Crypto.cs | 22 +------------------ .../ManualTests/DataCommon/DataTestUtility.cs | 5 +---- 4 files changed, 7 insertions(+), 37 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs index 3f5a50657e..93792a7b62 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -204,11 +204,9 @@ internal bool IsColumnEncryptionEnabled } } - internal bool ShouldUseEnclaveBasedWorkflow - { - get { return (!string.IsNullOrWhiteSpace(_activeConnection.EnclaveAttestationUrl) || Connection.AttestationProtocol == SqlConnectionAttestationProtocol.None) && - IsColumnEncryptionEnabled; } - } + internal bool ShouldUseEnclaveBasedWorkflow => + (!string.IsNullOrWhiteSpace(_activeConnection.EnclaveAttestationUrl) || Connection.AttestationProtocol == SqlConnectionAttestationProtocol.None) && + IsColumnEncryptionEnabled; /// /// Per-command custom providers. It can be provided by the user and can be set more than once. diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs index 7062d69a6b..ec7b36b400 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -160,14 +160,9 @@ internal bool IsColumnEncryptionEnabled } } - internal bool ShouldUseEnclaveBasedWorkflow - { - get - { - return (!string.IsNullOrWhiteSpace(_activeConnection.EnclaveAttestationUrl) || Connection.AttestationProtocol == SqlConnectionAttestationProtocol.None) && + internal bool ShouldUseEnclaveBasedWorkflow => + (!string.IsNullOrWhiteSpace(_activeConnection.EnclaveAttestationUrl) || Connection.AttestationProtocol == SqlConnectionAttestationProtocol.None) && IsColumnEncryptionEnabled; - } - } internal ConcurrentDictionary keysToBeSentToEnclave; internal bool requiresEnclaveComputations = false; diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs index 76433edc4c..d1e6c71527 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.Crypto.cs @@ -114,7 +114,7 @@ private SqlColumnEncryptionEnclaveProvider GetEnclaveProvider(SqlConnectionAttes if (sqlColumnEncryptionEnclaveProvider == null) { - throw SQL.EnclaveProviderNotFound(enclaveType, ConvertAttestationProtocolToString(attestationProtocol)); + throw SQL.EnclaveProviderNotFound(enclaveType, attestationProtocol.ToString()); } return sqlColumnEncryptionEnclaveProvider; @@ -206,25 +206,5 @@ internal byte[] GetSerializedAttestationParameters(SqlEnclaveAttestationParamete return CombineByteArrays(attestationProtocolBytes, attestationProtocolInputLengthBytes, attestationProtocolInputBytes, clientDHPublicKeyLengthBytes, clientDHPublicKey); } - - private string ConvertAttestationProtocolToString(SqlConnectionAttestationProtocol attestationProtocol) - { - switch (attestationProtocol) - { - case SqlConnectionAttestationProtocol.AAS: - return "AAS"; - - case SqlConnectionAttestationProtocol.HGS: - return "HGS"; - -#if ENCLAVE_SIMULATOR - case SqlConnectionAttestationProtocol.None: - return "None"; -#endif - - default: - return "NotSpecified"; - } - } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index d13d20638a..6c31280c0a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -304,10 +304,7 @@ public static bool AreConnStringSetupForAE() return AEConnStrings.Count > 0 && IsNotAzureSynapse(); } - public static bool IsSGXEnclaveConnStringSetup() - { - return !string.IsNullOrEmpty(TCPConnectionStringAASSGX); - } + public static bool IsSGXEnclaveConnStringSetup() => !string.IsNullOrEmpty(TCPConnectionStringAASSGX); public static bool IsAADPasswordConnStrSetup() { From 6c1e08068e55d06f474c54ed9d474e3d4853d7b3 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Fri, 21 Jan 2022 10:51:38 -0800 Subject: [PATCH 23/25] address feedback --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 20 +------------------ .../src/Microsoft/Data/SqlClient/TdsParser.cs | 20 +------------------ .../ConnectionStringBuilderShould.cs | 5 +++-- 3 files changed, 5 insertions(+), 40 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 97800fe334..cdea8f5892 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -3200,7 +3200,7 @@ private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) // Check if the attestation protocol is specified and supports the enclave type. if (SqlConnectionAttestationProtocol.NotSpecified != attestationProtocol && !IsValidAttestationProtocol(attestationProtocol, EnclaveType)) { - throw SQL.AttestationProtocolNotSupportEnclaveType(ConvertAttestationProtocolToString(attestationProtocol), EnclaveType); + throw SQL.AttestationProtocolNotSupportEnclaveType(attestationProtocol.ToString(), EnclaveType); } } } @@ -3250,24 +3250,6 @@ private bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol attesta return true; } - private string ConvertAttestationProtocolToString(SqlConnectionAttestationProtocol attestationProtocol) - { - switch (attestationProtocol) - { - case SqlConnectionAttestationProtocol.AAS: - return "AAS"; - - case SqlConnectionAttestationProtocol.HGS: - return "HGS"; - - case SqlConnectionAttestationProtocol.None: - return "None"; - - default: - return "NotSpecified"; - } - } - private bool TryReadByteString(TdsParserStateObject stateObj, out string value) { value = string.Empty; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 44ec6809fd..c84d76715e 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -3656,7 +3656,7 @@ private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) // Check if the attestation protocol is specified and supports the enclave type. if (attestationProtocol != SqlConnectionAttestationProtocol.NotSpecified && !IsValidAttestationProtocol(attestationProtocol, EnclaveType)) { - throw SQL.AttestationProtocolNotSupportEnclaveType(ConvertAttestationProtocolToString(attestationProtocol), EnclaveType); + throw SQL.AttestationProtocolNotSupportEnclaveType(attestationProtocol.ToString(), EnclaveType); } } } @@ -3706,24 +3706,6 @@ private bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol attesta return true; } - private string ConvertAttestationProtocolToString(SqlConnectionAttestationProtocol attestationProtocol) - { - switch (attestationProtocol) - { - case SqlConnectionAttestationProtocol.AAS: - return "AAS"; - - case SqlConnectionAttestationProtocol.HGS: - return "HGS"; - - case SqlConnectionAttestationProtocol.None: - return "None"; - - default: - return "NotSpecified"; - } - } - private bool TryReadByteString(TdsParserStateObject stateObj, out string value) { value = string.Empty; diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs index d7483a5e76..b16c0cc346 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs @@ -98,7 +98,7 @@ public void TestSqlConnectionStringAttestationProtocol() connectionStringBuilder4.Clear(); Assert.Equal(SqlConnectionAttestationProtocol.NotSpecified, connectionStringBuilder4.AttestationProtocol); - Assert.True(string.IsNullOrEmpty(connectionStringBuilder4.DataSource)); + Assert.Empty(connectionStringBuilder4.DataSource); } [Fact] @@ -336,7 +336,8 @@ public void TestSqlConnectionStringBuilderTryGetValue(SqlConnectionColumnEncrypt connectionStringBuilder.AttestationProtocol = SqlConnectionAttestationProtocol.None; - Assert.True(connectionStringBuilder.TryGetValue(@"Attestation Protocol", out outputValue)); + Assert.True(connectionStringBuilder.TryGetValue(@"Attestation Protocol", out outputValue), + "'Attestation Protocol'' key not found in SqlConnectionStringBuilder"); Assert.Equal(SqlConnectionAttestationProtocol.None, outputValue); } From 019200cc53504d9cce11103bf00a954b4b52b6ea Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Fri, 21 Jan 2022 14:07:18 -0800 Subject: [PATCH 24/25] update tests --- .../ConnectionStringBuilderShould.cs | 6 ++++++ .../AlwaysEncryptedTests/SqlConnectionShould.cs | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs index b16c0cc346..556617208f 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs @@ -142,14 +142,20 @@ public void TestSqlConnectionStringBuilderEquivilantTo_AttestationProtocol() // Use the EquivalentTo function to compare both the builder objects and make sure the result is expected. Assert.True(connectionStringBuilder1.EquivalentTo(connectionStringBuilder2)); Assert.True(connectionStringBuilder1.EquivalentTo(connectionStringBuilder3)); + Assert.Equal(connectionStringBuilder1.AttestationProtocol, connectionStringBuilder2.AttestationProtocol); + Assert.Equal(connectionStringBuilder1.AttestationProtocol, connectionStringBuilder3.AttestationProtocol); connectionStringBuilder2.AttestationProtocol = protocol2; Assert.True(!connectionStringBuilder1.EquivalentTo(connectionStringBuilder2)); Assert.True(!connectionStringBuilder3.EquivalentTo(connectionStringBuilder2)); + Assert.NotEqual(connectionStringBuilder1.AttestationProtocol, connectionStringBuilder2.AttestationProtocol); + Assert.NotEqual(connectionStringBuilder3.AttestationProtocol, connectionStringBuilder2.AttestationProtocol); connectionStringBuilder3.AttestationProtocol = protocol3; Assert.True(!connectionStringBuilder1.EquivalentTo(connectionStringBuilder3)); Assert.True(!connectionStringBuilder2.EquivalentTo(connectionStringBuilder3)); + Assert.NotEqual(connectionStringBuilder1.AttestationProtocol, connectionStringBuilder3.AttestationProtocol); + Assert.NotEqual(connectionStringBuilder2.AttestationProtocol, connectionStringBuilder3.AttestationProtocol); } diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlConnectionShould.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlConnectionShould.cs index faa48c7763..1669b228f7 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlConnectionShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlConnectionShould.cs @@ -151,5 +151,16 @@ SqlCommandColumnEncryptionSetting sqlCommandColumnEncryptionSetting_2 } } } + + [Fact] + public void TestInvalidAttestationProtocolInConnectionString() + { + string connectionString = "Data Source=localhost; Initial Catalog = testdb; Column Encryption Setting=Enabled;"; + ArgumentException ex = Assert.Throws(() => new SqlConnection(connectionString + "Attestation protocol=invalid")); + Assert.Null(ex.InnerException); + Assert.NotNull(ex.Message); + Assert.Contains("Invalid value for key 'Attestation Protocol'", ex.Message); + Assert.Null(ex.ParamName); + } } } From f226666b74359bc8aceafe3e9f6e056b60e5131b Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Mon, 24 Jan 2022 10:04:06 -0800 Subject: [PATCH 25/25] Update src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs Co-authored-by: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> --- .../AlwaysEncryptedTests/ConnectionStringBuilderShould.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs index 556617208f..aa042ffb65 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ConnectionStringBuilderShould.cs @@ -148,14 +148,12 @@ public void TestSqlConnectionStringBuilderEquivilantTo_AttestationProtocol() connectionStringBuilder2.AttestationProtocol = protocol2; Assert.True(!connectionStringBuilder1.EquivalentTo(connectionStringBuilder2)); Assert.True(!connectionStringBuilder3.EquivalentTo(connectionStringBuilder2)); - Assert.NotEqual(connectionStringBuilder1.AttestationProtocol, connectionStringBuilder2.AttestationProtocol); - Assert.NotEqual(connectionStringBuilder3.AttestationProtocol, connectionStringBuilder2.AttestationProtocol); + Assert.Equal(protocol2, connectionStringBuilder2.AttestationProtocol); connectionStringBuilder3.AttestationProtocol = protocol3; Assert.True(!connectionStringBuilder1.EquivalentTo(connectionStringBuilder3)); Assert.True(!connectionStringBuilder2.EquivalentTo(connectionStringBuilder3)); - Assert.NotEqual(connectionStringBuilder1.AttestationProtocol, connectionStringBuilder3.AttestationProtocol); - Assert.NotEqual(connectionStringBuilder2.AttestationProtocol, connectionStringBuilder3.AttestationProtocol); + Assert.Equal(protocol3, connectionStringBuilder3.AttestationProtocol); }