From 30cd14cb2a1c061c24dd037efd3b96be3666c869 Mon Sep 17 00:00:00 2001 From: Jeff Wasty Date: Thu, 20 Oct 2022 13:03:39 -0700 Subject: [PATCH 1/8] Fixed none to work property again. --- .../jdbc/SQLServerNoneEnclaveProvider.java | 161 ++++++------------ .../com/microsoft/sqlserver/jdbc/TestApp.java | 129 ++++++++++++++ 2 files changed, 183 insertions(+), 107 deletions(-) create mode 100644 src/test/java/com/microsoft/sqlserver/jdbc/TestApp.java diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java index c0045461e..ae3a22e66 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java @@ -5,48 +5,50 @@ package com.microsoft.sqlserver.jdbc; -import static java.nio.charset.StandardCharsets.UTF_16LE; - +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.GeneralSecurityException; -import java.security.SecureRandom; +import java.security.NoSuchAlgorithmException; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.text.MessageFormat; +import java.time.Instant; import java.util.ArrayList; +import java.util.Collection; +import java.util.Hashtable; /** * - * Provides the implementation of the NONE Enclave Provider. This enclave provider does not use attestation. + * Provides the implementation of the VSM Enclave Provider. The enclave provider encapsulates the client-side + * implementation details of the enclave attestation protocol. * */ public class SQLServerNoneEnclaveProvider implements ISQLServerEnclaveProvider { - private static final EnclaveSessionCache enclaveCache = new EnclaveSessionCache(); - + private static EnclaveSessionCache enclaveCache = new EnclaveSessionCache(); private NoneAttestationParameters noneParams = null; private NoneAttestationResponse noneResponse = null; private String attestationUrl = null; private EnclaveSession enclaveSession = null; - /** - * default constructor - */ - public SQLServerNoneEnclaveProvider() {} - @Override public void getAttestationParameters(String url) throws SQLServerException { if (null == noneParams) { attestationUrl = url; - try { - noneParams = new NoneAttestationParameters(attestationUrl); - } catch (IOException e) { - SQLServerException.makeFromDriverError(null, this, e.getLocalizedMessage(), "0", false); - } + noneParams = new NoneAttestationParameters(); } } @@ -54,12 +56,6 @@ public void getAttestationParameters(String url) throws SQLServerException { public ArrayList createEnclaveSession(SQLServerConnection connection, SQLServerStatement statement, String userSql, String preparedTypeDefinitions, Parameter[] params, ArrayList parameterNames) throws SQLServerException { - - /* - * 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). - */ - // Check if the session exists in our cache StringBuilder keyLookup = new StringBuilder(connection.getServerName()).append(connection.getCatalog()) .append(attestationUrl); @@ -73,6 +69,8 @@ public ArrayList createEnclaveSession(SQLServerConnection connection, SQ if (connection.enclaveEstablished()) { return b; } else if (null != noneResponse && !connection.enclaveEstablished()) { + + // If not, set it up try { enclaveSession = new EnclaveSession(noneResponse.getSessionID(), noneParams.createSessionSecret(noneResponse.getDHpublicKey())); @@ -100,16 +98,6 @@ public EnclaveSession getEnclaveSession() { return enclaveSession; } - private void validateAttestationResponse() throws SQLServerException { - if (null != noneResponse) { - try { - noneResponse.validateDHPublicKey(); - } catch (GeneralSecurityException e) { - SQLServerException.makeFromDriverError(null, this, e.getLocalizedMessage(), "0", false); - } - } - } - private ArrayList describeParameterEncryption(SQLServerConnection connection, SQLServerStatement statement, String userSql, String preparedTypeDefinitions, Parameter[] params, ArrayList parameterNames) throws SQLServerException { @@ -124,17 +112,15 @@ private ArrayList describeParameterEncryption(SQLServerConnection connec if (null == rs) { // No results. Meaning no parameter. // Should never happen. - return enclaveRequestedCEKs; + return enclaveRequestedCEKs; } processSDPEv1(userSql, preparedTypeDefinitions, params, parameterNames, connection, statement, stmt, rs, enclaveRequestedCEKs); - // Process the third result set. + // Process the third resultset. if (connection.isAEv2() && stmt.getMoreResults()) { - try (ResultSet hgsRs = stmt.getResultSet()) { - if (hgsRs.next()) { - noneResponse = new NoneAttestationResponse(hgsRs.getBytes(1)); - // This validates and establishes the enclave session if valid - validateAttestationResponse(); + try (ResultSet noneRs = (SQLServerResultSet) stmt.getResultSet()) { + if (noneRs.next()) { + noneResponse = new NoneAttestationResponse(noneRs.getBytes(1)); } else { SQLServerException.makeFromDriverError(null, this, SQLServerException.getErrString("R_UnableRetrieveParameterMetadata"), "0", @@ -157,30 +143,12 @@ private ArrayList describeParameterEncryption(SQLServerConnection connec } -/** - * - * Represents the serialization of the request the client sends to the SQL Server while setting up a session. - * - */ class NoneAttestationParameters extends BaseAttestationRequest { - // Type 2 is NONE, sent as Little Endian 0x20000000 - private static final byte[] ENCLAVE_TYPE = new byte[] {0x2, 0x0, 0x0, 0x0}; - // Nonce length is always 256 - private static final byte[] NONCE_LENGTH = new byte[] {0x0, 0x1, 0x0, 0x0}; - private final byte[] nonce = new byte[256]; - - NoneAttestationParameters(String attestationUrl) throws SQLServerException, IOException { - byte[] attestationUrlBytes = (attestationUrl + '\0').getBytes(UTF_16LE); - - ByteArrayOutputStream os = new ByteArrayOutputStream(); - os.write(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(attestationUrlBytes.length).array()); - os.write(attestationUrlBytes); - os.write(NONCE_LENGTH); - new SecureRandom().nextBytes(nonce); - os.write(nonce); - enclaveChallenge = os.toByteArray(); + private static byte ENCLAVE_TYPE[] = new byte[] {0x2, 0x0, 0x0, 0x0}; + NoneAttestationParameters() throws SQLServerException { + enclaveChallenge = new byte[] {0x0, 0x0, 0x0, 0x0}; initBcryptECDH(); } @@ -188,7 +156,6 @@ class NoneAttestationParameters extends BaseAttestationRequest { byte[] getBytes() throws IOException { ByteArrayOutputStream os = new ByteArrayOutputStream(); os.write(ENCLAVE_TYPE); - os.write(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(enclaveChallenge.length).array()); os.write(enclaveChallenge); os.write(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(ENCLAVE_LENGTH).array()); os.write(ECDH_MAGIC); @@ -196,59 +163,39 @@ byte[] getBytes() throws IOException { os.write(y); return os.toByteArray(); } - - byte[] getNonce() { - return nonce; - } } -/** - * - * Represents the deserialization of the byte payload the client receives from the SQL Server while setting up a - * session. - * - */ +@SuppressWarnings("unused") class NoneAttestationResponse extends BaseAttestationResponse { - NoneAttestationResponse(byte[] b) throws SQLServerException { /*- - * Protocol format: - * 1. Total Size of the attestation blob as UINT - * 2. Size of Enclave RSA public key as UINT - * 3. Size of Attestation token as UINT - * 4. Enclave Type as UINT - * 5. Enclave RSA public key (raw key, of length #2) - * 6. Attestation token (of length #3) - * 7. Size of Session ID was UINT - * 8. Session id value - * 9. Size of enclave ECDH public key - * 10. Enclave ECDH public key (of length #9) - */ - ByteBuffer response = ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN); - this.totalSize = response.getInt(); - this.identitySize = response.getInt(); - this.attestationTokenSize = response.getInt(); - this.enclaveType = response.getInt(); // 1 for VBS, 2 for SGX - - enclavePK = new byte[identitySize]; - byte[] attestationToken = new byte[attestationTokenSize]; - - response.get(enclavePK, 0, identitySize); - response.get(attestationToken, 0, attestationTokenSize); - - this.sessionInfoSize = response.getInt(); - response.get(sessionID, 0, 8); - this.DHPKsize = response.getInt(); - this.DHPKSsize = response.getInt(); - - DHpublicKey = new byte[DHPKsize]; - publicKeySig = new byte[DHPKSsize]; - - response.get(DHpublicKey, 0, DHPKsize); - response.get(publicKeySig, 0, DHPKSsize); + * Parse the attestation response. + * + * Total Size of the response - 4B + * Session Info Size - 4B + * Session ID - 8B + * DH Public Key Size - 4B + * DH Public Key Signature Size - 4B + * DH Public Key - DHPKsize bytes + * DH Public Key Signature - DHPKSsize bytes + */ + ByteBuffer response = (null != b) ? ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN) : null; + if (null != response) { + this.totalSize = response.getInt(); + this.sessionInfoSize = response.getInt(); + response.get(sessionID, 0, 8); + this.DHPKsize = response.getInt(); + this.DHPKSsize = response.getInt(); + + DHpublicKey = new byte[DHPKsize]; + publicKeySig = new byte[DHPKSsize]; + + response.get(DHpublicKey, 0, DHPKsize); + response.get(publicKeySig, 0, DHPKSsize); + } - if (0 != response.remaining()) { + if (null == response || 0 != response.remaining()) { SQLServerException.makeFromDriverError(null, this, SQLServerResource.getResource("R_EnclaveResponseLengthError"), "0", false); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/TestApp.java b/src/test/java/com/microsoft/sqlserver/jdbc/TestApp.java new file mode 100644 index 000000000..772c02bc0 --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/jdbc/TestApp.java @@ -0,0 +1,129 @@ +package com.microsoft.sqlserver.jdbc; + +import com.microsoft.sqlserver.jdbc.AlwaysEncrypted.AESetup;import com.microsoft.sqlserver.testframework.Constants;import com.microsoft.sqlserver.testframework.PrepUtil;import org.junit.jupiter.api.BeforeAll; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException;import java.sql.Statement;import java.util.Properties;import java.util.logging.LogManager; +import static org.junit.jupiter.api.Assertions.assertTrue;import static org.junit.jupiter.api.Assertions.fail; + +public class TestApp { + + public static String connectionString = "jdbc:sqlserver://drivers-ae-vbs-none.database.windows.net;" + + "userName=employee;password=Moonshine4me;databaseName=ContosoHR;"; + public static String AETestConnectionString = ""; + public static Properties AEInfo; + + public static void main(String[] args) throws Exception { + setAEConnectionString("drivers-ae-vbs-none.database.windows.net", " ", "NONE"); + String cekJks = Constants.CEK_NAME + "_JKS"; + String varcharTableSimple[][] = {{"Varchar", "varchar(20) COLLATE LATIN1_GENERAL_BIN2", "VARCHAR"}}; + + try (SQLServerConnection c = PrepUtil.getConnection(AETestConnectionString, AEInfo); + Statement s = c.createStatement()) { + createTable("CHAR_TABLE_AE", "CEK1", varcharTableSimple); + PreparedStatement pstmt = c.prepareStatement("INSERT INTO " + "CHAR_TABLE_AE" + " VALUES (?,?,?)"); + pstmt.setString(1, "a"); + pstmt.setString(2, "b"); + pstmt.setString(3, "test"); + pstmt.execute(); + pstmt = c.prepareStatement("SELECT * FROM " + "CHAR_TABLE_AE" + " WHERE RANDOMIZEDVarchar LIKE ?"); + pstmt.setString(1, "t%"); + try (ResultSet rs = pstmt.executeQuery()) { + while (rs.next()) { + assertTrue(rs.getString(1).equalsIgnoreCase("a"), "rs.getString(1)=" + rs.getString(1)); + assertTrue(rs.getString(2).equalsIgnoreCase("b"), "rs.getString(2)=" + rs.getString(2)); + assertTrue(rs.getString(3).equalsIgnoreCase("test"), "rs.getString(3)=" + rs.getString(3)); + } + } + } + } + +// @BeforeAll +// public static void setupAETest() throws Exception { +// +// String javaKeyPath = TestUtils.getCurrentClassPath() + Constants.JKS_NAME; +// SQLServerColumnEncryptionKeyStoreProvider jksProvider = new SQLServerColumnEncryptionJavaKeyStoreProvider(javaKeyPath, +// Constants.JKS_SECRET.toCharArray()); +// +// AEInfo = new Properties(); +// AEInfo.setProperty("ColumnEncryptionSetting", Constants.ENABLED); +// AEInfo.setProperty("keyStoreAuthentication", Constants.JAVA_KEY_STORE_SECRET); +// AEInfo.setProperty("keyStoreLocation", javaKeyPath); +// AEInfo.setProperty("keyStoreSecret", Constants.JKS_SECRET); +// +// createCMK(AETestConnectionString, "CMK1", Constants.JAVA_KEY_STORE_NAME, "lp-37941554-7af9-4e74-a646-8772dd264012", +// Constants.CMK_SIGNATURE); +// createCEK(AETestConnectionString, "CMK1", "CEK1", jksProvider); +// } + + protected static void createTable(String tableName, String cekName, String table[][]) throws SQLException { + String encryptSql = " ENCRYPTED WITH (ENCRYPTION_TYPE = %s, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'," + + " COLUMN_ENCRYPTION_KEY = %s"; + String createSql = "CREATE TABLE %s (%s)"; + try (SQLServerConnection con = (SQLServerConnection) PrepUtil.getConnection(AETestConnectionString, AEInfo); + SQLServerStatement stmt = (SQLServerStatement) con.createStatement()) { + StringBuilder sql = new StringBuilder(16); + for(String[] strings: table){ + sql.append("PLAIN").append(strings[0]).append(" ").append(strings[1]).append(" NULL,"); + sql.append("DETERMINISTIC").append(strings[0]).append(" ").append(strings[1]) + .append(String.format(encryptSql, "DETERMINISTIC", cekName)).append(") NULL,"); + sql.append("RANDOMIZED").append(strings[0]).append(" ").append(strings[1]) + .append(String.format(encryptSql, "RANDOMIZED", cekName)).append(") NULL,"); + } + TestUtils.dropTableIfExists(tableName, stmt); + sql=new StringBuilder(String.format(createSql, tableName, sql.toString())); + stmt.execute(sql.toString()); + stmt.execute("DBCC FREEPROCCACHE"); + } catch (SQLException e) { + fail(e.getMessage()); + } + } + + static void setAEConnectionString(String serverName, String url, String protocol) { + String enclaveProperties = "serverName=" + serverName + ";" + Constants.ENCLAVE_ATTESTATIONURL + "=" + url + ";" + + Constants.ENCLAVE_ATTESTATIONPROTOCOL + "=" + protocol; + AETestConnectionString = connectionString + ";sendTimeAsDateTime=false" + ";columnEncryptionSetting=enabled" + + ";" + enclaveProperties; + } + +// protected static void createCMK(String connectionString, String cmkName, String keyStoreName, String keyPath, +// String signature) throws SQLException { +// try (SQLServerConnection con = (SQLServerConnection) PrepUtil +// .getConnection(connectionString + ";sendTimeAsDateTime=false", AEInfo); +// SQLServerStatement stmt = (SQLServerStatement) con.createStatement()) { +// String sql = " if not exists (SELECT name from sys.column_master_keys where name='" + cmkName + "')" +// + " begin" + " CREATE COLUMN MASTER KEY " + cmkName + " WITH (KEY_STORE_PROVIDER_NAME = '" +// + keyStoreName + "', KEY_PATH = '" + keyPath + "'" +// + (TestUtils.isAEv2(con) ? ",ENCLAVE_COMPUTATIONS (SIGNATURE = " + signature + ")) end" : ") end"); +// stmt.execute(sql); +// } +// } +// +// protected static void createCEK(String connectionString, String cmkName, String cekName, +// SQLServerColumnEncryptionKeyStoreProvider storeProvider) throws SQLException { +// try (SQLServerConnection con = (SQLServerConnection) PrepUtil +// .getConnection(connectionString + ";sendTimeAsDateTime=false", AEInfo); +// SQLServerStatement stmt = (SQLServerStatement) con.createStatement()) { +// byte[] valuesDefault = Constants.CEK_STRING.getBytes(); +// String encryptedValue; +// +// if (storeProvider instanceof SQLServerColumnEncryptionJavaKeyStoreProvider) { +// byte[] key = storeProvider.encryptColumnEncryptionKey("lp-37941554-7af9-4e74-a646-8772dd264012", Constants.CEK_ALGORITHM, +// valuesDefault); +// encryptedValue = "0x" + TestUtils.bytesToHexString(key, key.length); +// } else if (storeProvider instanceof SQLServerColumnEncryptionAzureKeyVaultProvider) { +// byte[] key = storeProvider.encryptColumnEncryptionKey("https://susanakv.vault.azure.net/keys/Always-Encrypted-Auto1/86412ce2ec8746f4ab1ba159f6d585e6", Constants.CEK_ALGORITHM, +// valuesDefault); +// encryptedValue = "0x" + TestUtils.bytesToHexString(key, key.length); +// } else { +// encryptedValue = Constants.CEK_ENCRYPTED_VALUE; +// } +// +// String sql = "if not exists (SELECT name from sys.column_encryption_keys where name='" + cekName + "')" +// + " begin" + " CREATE COLUMN ENCRYPTION KEY " + cekName + " WITH VALUES " + "(COLUMN_MASTER_KEY = " +// + cmkName + ", ALGORITHM = '" + Constants.CEK_ALGORITHM + "', ENCRYPTED_VALUE = " + encryptedValue +// + ") end;"; +// stmt.execute(sql); +// } +// } +} From 76e79ce035d27cce4564600cf9c7e83805790d3b Mon Sep 17 00:00:00 2001 From: Jeff Wasty Date: Fri, 21 Oct 2022 09:55:50 -0700 Subject: [PATCH 2/8] Temp code change to see if hotswapping db works. --- .../microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java index 820fe5b0e..666fafc57 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java @@ -25,7 +25,7 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; -import org.junit.platform.runner.JUnitPlatform; +import org.junit.jupiter.api.Test;import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; import com.microsoft.sqlserver.jdbc.RandomData; @@ -216,6 +216,12 @@ public static void setupAETest() throws Exception { param[i][0] = serverName; param[i][1] = url; param[i][2] = protocol; + + if (serverName.equalsIgnoreCase("drivers-ae-vbs-none.database.windows.net")) { + connectionString = TestUtils.addOrOverrideProperty(connectionString, "databaseName", "TestDb"); + } else { + connectionString = TestUtils.addOrOverrideProperty(connectionString, "databaseName", "master"); + } setAEConnectionString(serverName, url, protocol); From 645b2c63f769465601f04c80e8d31a2a87143f77 Mon Sep 17 00:00:00 2001 From: Jeff Wasty Date: Fri, 21 Oct 2022 15:20:29 -0700 Subject: [PATCH 3/8] Clean up NONE according to Eclipse, and revert the db hotswapping. --- .../jdbc/SQLServerNoneEnclaveProvider.java | 24 ++++--------------- .../jdbc/AlwaysEncrypted/AESetup.java | 6 ----- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java index ae3a22e66..42a2e4324 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java @@ -5,29 +5,15 @@ package com.microsoft.sqlserver.jdbc; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.GeneralSecurityException; -import java.security.NoSuchAlgorithmException; -import java.security.Signature; -import java.security.SignatureException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.spec.MGF1ParameterSpec; -import java.security.spec.PSSParameterSpec; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.text.MessageFormat; -import java.time.Instant; import java.util.ArrayList; -import java.util.Collection; -import java.util.Hashtable; /** @@ -112,13 +98,13 @@ private ArrayList describeParameterEncryption(SQLServerConnection connec if (null == rs) { // No results. Meaning no parameter. // Should never happen. - return enclaveRequestedCEKs; + return enclaveRequestedCEKs; } processSDPEv1(userSql, preparedTypeDefinitions, params, parameterNames, connection, statement, stmt, rs, enclaveRequestedCEKs); // Process the third resultset. if (connection.isAEv2() && stmt.getMoreResults()) { - try (ResultSet noneRs = (SQLServerResultSet) stmt.getResultSet()) { + try (ResultSet noneRs = stmt.getResultSet()) { if (noneRs.next()) { noneResponse = new NoneAttestationResponse(noneRs.getBytes(1)); } else { @@ -133,10 +119,9 @@ private ArrayList describeParameterEncryption(SQLServerConnection connec } catch (SQLException | IOException e) { if (e instanceof SQLServerException) { throw (SQLServerException) e; - } else { - throw new SQLServerException(SQLServerException.getErrString("R_UnableRetrieveParameterMetadata"), null, - 0, e); } + throw new SQLServerException(SQLServerException.getErrString("R_UnableRetrieveParameterMetadata"), null, 0, + e); } return enclaveRequestedCEKs; } @@ -166,7 +151,6 @@ byte[] getBytes() throws IOException { } -@SuppressWarnings("unused") class NoneAttestationResponse extends BaseAttestationResponse { NoneAttestationResponse(byte[] b) throws SQLServerException { /*- diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java index 666fafc57..4eae8397d 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java @@ -216,12 +216,6 @@ public static void setupAETest() throws Exception { param[i][0] = serverName; param[i][1] = url; param[i][2] = protocol; - - if (serverName.equalsIgnoreCase("drivers-ae-vbs-none.database.windows.net")) { - connectionString = TestUtils.addOrOverrideProperty(connectionString, "databaseName", "TestDb"); - } else { - connectionString = TestUtils.addOrOverrideProperty(connectionString, "databaseName", "master"); - } setAEConnectionString(serverName, url, protocol); From ea62c537f2c09d39d4013749fe608f357f9db09e Mon Sep 17 00:00:00 2001 From: Jeff Wasty Date: Mon, 24 Oct 2022 09:45:51 -0700 Subject: [PATCH 4/8] Added an exclusion in EnclavePackageTest::testInvalidProperties, as NONE should be allowed without a protocol. --- .../microsoft/sqlserver/jdbc/EnclavePackageTest.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/EnclavePackageTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/EnclavePackageTest.java index 68eceb53c..7856e1b37 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/EnclavePackageTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/EnclavePackageTest.java @@ -247,7 +247,8 @@ public static void testBasicConnection(String cString, String protocol) throws E } /** - * Tests invalid connection property combinations. + * Tests invalid connection property combinations. NONE protocol is allowed without an attestation URL, and so + * an exclusion is defined for NONE. * * @throws Exception */ @@ -262,9 +263,11 @@ public static void testInvalidProperties(String serverName, String url, String p testInvalidProperties(TestUtils.removeProperty(connectionStringEnclave, "enclaveAttestationProtocol"), "R_enclavePropertiesError"); - // enclaveAttestationProtocol without enclaveAttestationUrl - testInvalidProperties(TestUtils.addOrOverrideProperty(connectionStringEnclave, "enclaveAttestationUrl", ""), - "R_enclavePropertiesError"); + // enclaveAttestationProtocol without enclaveAttestationUrl (given that it is not NONE) + if (!String.valueOf(AttestationProtocol.NONE).equals(protocol)) { + testInvalidProperties(TestUtils.addOrOverrideProperty(connectionStringEnclave, "enclaveAttestationUrl", ""), + "R_enclavePropertiesError"); + } // bad enclaveAttestationProtocol testInvalidProperties( From df83dffafd63dd2233cfdffffecc779c06af1f57 Mon Sep 17 00:00:00 2001 From: Jeff Wasty Date: Wed, 26 Oct 2022 12:12:38 -0700 Subject: [PATCH 5/8] Cleanup --- .../jdbc/SQLServerNoneEnclaveProvider.java | 32 ++++- .../jdbc/AlwaysEncrypted/AESetup.java | 4 +- .../sqlserver/jdbc/EnclavePackageTest.java | 4 +- .../com/microsoft/sqlserver/jdbc/TestApp.java | 129 ------------------ 4 files changed, 30 insertions(+), 139 deletions(-) delete mode 100644 src/test/java/com/microsoft/sqlserver/jdbc/TestApp.java diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java index 42a2e4324..26f63f28c 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java @@ -18,18 +18,22 @@ /** * - * Provides the implementation of the VSM Enclave Provider. The enclave provider encapsulates the client-side - * implementation details of the enclave attestation protocol. + * Provides the implementation of the NONE Enclave Provider. This enclave provider does not use attestation. * */ public class SQLServerNoneEnclaveProvider implements ISQLServerEnclaveProvider { - private static EnclaveSessionCache enclaveCache = new EnclaveSessionCache(); + private static final EnclaveSessionCache enclaveCache = new EnclaveSessionCache(); private NoneAttestationParameters noneParams = null; private NoneAttestationResponse noneResponse = null; private String attestationUrl = null; private EnclaveSession enclaveSession = null; + /** + * default constructor + */ + public SQLServerNoneEnclaveProvider() {} + @Override public void getAttestationParameters(String url) throws SQLServerException { if (null == noneParams) { @@ -42,6 +46,12 @@ public void getAttestationParameters(String url) throws SQLServerException { public ArrayList createEnclaveSession(SQLServerConnection connection, SQLServerStatement statement, String userSql, String preparedTypeDefinitions, Parameter[] params, ArrayList parameterNames) throws SQLServerException { + + /* + * 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). + */ + // Check if the session exists in our cache StringBuilder keyLookup = new StringBuilder(connection.getServerName()).append(connection.getCatalog()) .append(attestationUrl); @@ -55,8 +65,6 @@ public ArrayList createEnclaveSession(SQLServerConnection connection, SQ if (connection.enclaveEstablished()) { return b; } else if (null != noneResponse && !connection.enclaveEstablished()) { - - // If not, set it up try { enclaveSession = new EnclaveSession(noneResponse.getSessionID(), noneParams.createSessionSecret(noneResponse.getDHpublicKey())); @@ -102,7 +110,7 @@ private ArrayList describeParameterEncryption(SQLServerConnection connec } processSDPEv1(userSql, preparedTypeDefinitions, params, parameterNames, connection, statement, stmt, rs, enclaveRequestedCEKs); - // Process the third resultset. + // Process the third result set. if (connection.isAEv2() && stmt.getMoreResults()) { try (ResultSet noneRs = stmt.getResultSet()) { if (noneRs.next()) { @@ -128,6 +136,11 @@ private ArrayList describeParameterEncryption(SQLServerConnection connec } +/** + * + * Represents the serialization of the request the client sends to the SQL Server while setting up a session. + * + */ class NoneAttestationParameters extends BaseAttestationRequest { // Type 2 is NONE, sent as Little Endian 0x20000000 private static byte ENCLAVE_TYPE[] = new byte[] {0x2, 0x0, 0x0, 0x0}; @@ -151,7 +164,14 @@ byte[] getBytes() throws IOException { } +/** + * + * Represents the deserialization of the byte payload the client receives from the SQL Server while setting up a + * session. + * + */ class NoneAttestationResponse extends BaseAttestationResponse { + NoneAttestationResponse(byte[] b) throws SQLServerException { /*- * Parse the attestation response. diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java index 4eae8397d..a3d18c127 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java @@ -25,7 +25,7 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test;import org.junit.platform.runner.JUnitPlatform; +import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; import com.microsoft.sqlserver.jdbc.RandomData; @@ -151,7 +151,7 @@ enum ColumnType { "PlainDecimal decimal(30)", "PlainNumeric numeric(30)"}; // junit test parameters: serverName, enclaveAttestationUrl, enclaveAttestationProtocol - static String[][] param = new String[(null == AbstractTest.enclaveServer ? 0 + static String[][] param = new String[(null == AbstractTest.enclaveServer ? 1 : AbstractTest.enclaveServer.length)][3]; /** diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/EnclavePackageTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/EnclavePackageTest.java index 7856e1b37..b7fa336f9 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/EnclavePackageTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/EnclavePackageTest.java @@ -256,8 +256,8 @@ public static void testInvalidProperties(String serverName, String url, String p setAEConnectionString(url, protocol); // enclaveAttestationUrl and enclaveAttestationProtocol without "columnEncryptionSetting" - testInvalidProperties(TestUtils.addOrOverrideProperty(connectionStringEnclave, "columnEncryptionSetting", - ColumnEncryptionSetting.Disabled.toString()), "R_enclavePropertiesError"); +// testInvalidProperties(TestUtils.addOrOverrideProperty(connectionStringEnclave, "columnEncryptionSetting", +// ColumnEncryptionSetting.Disabled.toString()), "R_enclavePropertiesError"); // enclaveAttestationUrl without enclaveAttestationProtocol testInvalidProperties(TestUtils.removeProperty(connectionStringEnclave, "enclaveAttestationProtocol"), diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/TestApp.java b/src/test/java/com/microsoft/sqlserver/jdbc/TestApp.java deleted file mode 100644 index 772c02bc0..000000000 --- a/src/test/java/com/microsoft/sqlserver/jdbc/TestApp.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.microsoft.sqlserver.jdbc; - -import com.microsoft.sqlserver.jdbc.AlwaysEncrypted.AESetup;import com.microsoft.sqlserver.testframework.Constants;import com.microsoft.sqlserver.testframework.PrepUtil;import org.junit.jupiter.api.BeforeAll; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException;import java.sql.Statement;import java.util.Properties;import java.util.logging.LogManager; -import static org.junit.jupiter.api.Assertions.assertTrue;import static org.junit.jupiter.api.Assertions.fail; - -public class TestApp { - - public static String connectionString = "jdbc:sqlserver://drivers-ae-vbs-none.database.windows.net;" - + "userName=employee;password=Moonshine4me;databaseName=ContosoHR;"; - public static String AETestConnectionString = ""; - public static Properties AEInfo; - - public static void main(String[] args) throws Exception { - setAEConnectionString("drivers-ae-vbs-none.database.windows.net", " ", "NONE"); - String cekJks = Constants.CEK_NAME + "_JKS"; - String varcharTableSimple[][] = {{"Varchar", "varchar(20) COLLATE LATIN1_GENERAL_BIN2", "VARCHAR"}}; - - try (SQLServerConnection c = PrepUtil.getConnection(AETestConnectionString, AEInfo); - Statement s = c.createStatement()) { - createTable("CHAR_TABLE_AE", "CEK1", varcharTableSimple); - PreparedStatement pstmt = c.prepareStatement("INSERT INTO " + "CHAR_TABLE_AE" + " VALUES (?,?,?)"); - pstmt.setString(1, "a"); - pstmt.setString(2, "b"); - pstmt.setString(3, "test"); - pstmt.execute(); - pstmt = c.prepareStatement("SELECT * FROM " + "CHAR_TABLE_AE" + " WHERE RANDOMIZEDVarchar LIKE ?"); - pstmt.setString(1, "t%"); - try (ResultSet rs = pstmt.executeQuery()) { - while (rs.next()) { - assertTrue(rs.getString(1).equalsIgnoreCase("a"), "rs.getString(1)=" + rs.getString(1)); - assertTrue(rs.getString(2).equalsIgnoreCase("b"), "rs.getString(2)=" + rs.getString(2)); - assertTrue(rs.getString(3).equalsIgnoreCase("test"), "rs.getString(3)=" + rs.getString(3)); - } - } - } - } - -// @BeforeAll -// public static void setupAETest() throws Exception { -// -// String javaKeyPath = TestUtils.getCurrentClassPath() + Constants.JKS_NAME; -// SQLServerColumnEncryptionKeyStoreProvider jksProvider = new SQLServerColumnEncryptionJavaKeyStoreProvider(javaKeyPath, -// Constants.JKS_SECRET.toCharArray()); -// -// AEInfo = new Properties(); -// AEInfo.setProperty("ColumnEncryptionSetting", Constants.ENABLED); -// AEInfo.setProperty("keyStoreAuthentication", Constants.JAVA_KEY_STORE_SECRET); -// AEInfo.setProperty("keyStoreLocation", javaKeyPath); -// AEInfo.setProperty("keyStoreSecret", Constants.JKS_SECRET); -// -// createCMK(AETestConnectionString, "CMK1", Constants.JAVA_KEY_STORE_NAME, "lp-37941554-7af9-4e74-a646-8772dd264012", -// Constants.CMK_SIGNATURE); -// createCEK(AETestConnectionString, "CMK1", "CEK1", jksProvider); -// } - - protected static void createTable(String tableName, String cekName, String table[][]) throws SQLException { - String encryptSql = " ENCRYPTED WITH (ENCRYPTION_TYPE = %s, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'," - + " COLUMN_ENCRYPTION_KEY = %s"; - String createSql = "CREATE TABLE %s (%s)"; - try (SQLServerConnection con = (SQLServerConnection) PrepUtil.getConnection(AETestConnectionString, AEInfo); - SQLServerStatement stmt = (SQLServerStatement) con.createStatement()) { - StringBuilder sql = new StringBuilder(16); - for(String[] strings: table){ - sql.append("PLAIN").append(strings[0]).append(" ").append(strings[1]).append(" NULL,"); - sql.append("DETERMINISTIC").append(strings[0]).append(" ").append(strings[1]) - .append(String.format(encryptSql, "DETERMINISTIC", cekName)).append(") NULL,"); - sql.append("RANDOMIZED").append(strings[0]).append(" ").append(strings[1]) - .append(String.format(encryptSql, "RANDOMIZED", cekName)).append(") NULL,"); - } - TestUtils.dropTableIfExists(tableName, stmt); - sql=new StringBuilder(String.format(createSql, tableName, sql.toString())); - stmt.execute(sql.toString()); - stmt.execute("DBCC FREEPROCCACHE"); - } catch (SQLException e) { - fail(e.getMessage()); - } - } - - static void setAEConnectionString(String serverName, String url, String protocol) { - String enclaveProperties = "serverName=" + serverName + ";" + Constants.ENCLAVE_ATTESTATIONURL + "=" + url + ";" - + Constants.ENCLAVE_ATTESTATIONPROTOCOL + "=" + protocol; - AETestConnectionString = connectionString + ";sendTimeAsDateTime=false" + ";columnEncryptionSetting=enabled" - + ";" + enclaveProperties; - } - -// protected static void createCMK(String connectionString, String cmkName, String keyStoreName, String keyPath, -// String signature) throws SQLException { -// try (SQLServerConnection con = (SQLServerConnection) PrepUtil -// .getConnection(connectionString + ";sendTimeAsDateTime=false", AEInfo); -// SQLServerStatement stmt = (SQLServerStatement) con.createStatement()) { -// String sql = " if not exists (SELECT name from sys.column_master_keys where name='" + cmkName + "')" -// + " begin" + " CREATE COLUMN MASTER KEY " + cmkName + " WITH (KEY_STORE_PROVIDER_NAME = '" -// + keyStoreName + "', KEY_PATH = '" + keyPath + "'" -// + (TestUtils.isAEv2(con) ? ",ENCLAVE_COMPUTATIONS (SIGNATURE = " + signature + ")) end" : ") end"); -// stmt.execute(sql); -// } -// } -// -// protected static void createCEK(String connectionString, String cmkName, String cekName, -// SQLServerColumnEncryptionKeyStoreProvider storeProvider) throws SQLException { -// try (SQLServerConnection con = (SQLServerConnection) PrepUtil -// .getConnection(connectionString + ";sendTimeAsDateTime=false", AEInfo); -// SQLServerStatement stmt = (SQLServerStatement) con.createStatement()) { -// byte[] valuesDefault = Constants.CEK_STRING.getBytes(); -// String encryptedValue; -// -// if (storeProvider instanceof SQLServerColumnEncryptionJavaKeyStoreProvider) { -// byte[] key = storeProvider.encryptColumnEncryptionKey("lp-37941554-7af9-4e74-a646-8772dd264012", Constants.CEK_ALGORITHM, -// valuesDefault); -// encryptedValue = "0x" + TestUtils.bytesToHexString(key, key.length); -// } else if (storeProvider instanceof SQLServerColumnEncryptionAzureKeyVaultProvider) { -// byte[] key = storeProvider.encryptColumnEncryptionKey("https://susanakv.vault.azure.net/keys/Always-Encrypted-Auto1/86412ce2ec8746f4ab1ba159f6d585e6", Constants.CEK_ALGORITHM, -// valuesDefault); -// encryptedValue = "0x" + TestUtils.bytesToHexString(key, key.length); -// } else { -// encryptedValue = Constants.CEK_ENCRYPTED_VALUE; -// } -// -// String sql = "if not exists (SELECT name from sys.column_encryption_keys where name='" + cekName + "')" -// + " begin" + " CREATE COLUMN ENCRYPTION KEY " + cekName + " WITH VALUES " + "(COLUMN_MASTER_KEY = " -// + cmkName + ", ALGORITHM = '" + Constants.CEK_ALGORITHM + "', ENCRYPTED_VALUE = " + encryptedValue -// + ") end;"; -// stmt.execute(sql); -// } -// } -} From 49374fc6b31f3d241e1c867b03d5b076c47b80a1 Mon Sep 17 00:00:00 2001 From: Jeff Wasty Date: Wed, 26 Oct 2022 12:16:04 -0700 Subject: [PATCH 6/8] Formatting again. --- .../sqlserver/jdbc/SQLServerNoneEnclaveProvider.java | 7 ++++--- .../microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java | 2 +- .../com/microsoft/sqlserver/jdbc/EnclavePackageTest.java | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java index 26f63f28c..0b339a778 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java @@ -24,6 +24,7 @@ public class SQLServerNoneEnclaveProvider implements ISQLServerEnclaveProvider { private static final EnclaveSessionCache enclaveCache = new EnclaveSessionCache(); + private NoneAttestationParameters noneParams = null; private NoneAttestationResponse noneResponse = null; private String attestationUrl = null; @@ -46,12 +47,12 @@ public void getAttestationParameters(String url) throws SQLServerException { public ArrayList createEnclaveSession(SQLServerConnection connection, SQLServerStatement statement, String userSql, String preparedTypeDefinitions, Parameter[] params, ArrayList parameterNames) throws SQLServerException { - + /* * 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). */ - + // Check if the session exists in our cache StringBuilder keyLookup = new StringBuilder(connection.getServerName()).append(connection.getCatalog()) .append(attestationUrl); @@ -171,7 +172,7 @@ byte[] getBytes() throws IOException { * */ class NoneAttestationResponse extends BaseAttestationResponse { - + NoneAttestationResponse(byte[] b) throws SQLServerException { /*- * Parse the attestation response. diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java index a3d18c127..820fe5b0e 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java @@ -151,7 +151,7 @@ enum ColumnType { "PlainDecimal decimal(30)", "PlainNumeric numeric(30)"}; // junit test parameters: serverName, enclaveAttestationUrl, enclaveAttestationProtocol - static String[][] param = new String[(null == AbstractTest.enclaveServer ? 1 + static String[][] param = new String[(null == AbstractTest.enclaveServer ? 0 : AbstractTest.enclaveServer.length)][3]; /** diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/EnclavePackageTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/EnclavePackageTest.java index b7fa336f9..7856e1b37 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/EnclavePackageTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/EnclavePackageTest.java @@ -256,8 +256,8 @@ public static void testInvalidProperties(String serverName, String url, String p setAEConnectionString(url, protocol); // enclaveAttestationUrl and enclaveAttestationProtocol without "columnEncryptionSetting" -// testInvalidProperties(TestUtils.addOrOverrideProperty(connectionStringEnclave, "columnEncryptionSetting", -// ColumnEncryptionSetting.Disabled.toString()), "R_enclavePropertiesError"); + testInvalidProperties(TestUtils.addOrOverrideProperty(connectionStringEnclave, "columnEncryptionSetting", + ColumnEncryptionSetting.Disabled.toString()), "R_enclavePropertiesError"); // enclaveAttestationUrl without enclaveAttestationProtocol testInvalidProperties(TestUtils.removeProperty(connectionStringEnclave, "enclaveAttestationProtocol"), From b4981588fbd1b889cef31ac98d57048141066562 Mon Sep 17 00:00:00 2001 From: Jeff Wasty Date: Wed, 26 Oct 2022 12:56:36 -0700 Subject: [PATCH 7/8] More formatting. --- .../microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java | 1 + .../com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java index 0b339a778..f3f02299c 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNoneEnclaveProvider.java @@ -143,6 +143,7 @@ private ArrayList describeParameterEncryption(SQLServerConnection connec * */ class NoneAttestationParameters extends BaseAttestationRequest { + // Type 2 is NONE, sent as Little Endian 0x20000000 private static byte ENCLAVE_TYPE[] = new byte[] {0x2, 0x0, 0x0, 0x0}; diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java index 820fe5b0e..a3d18c127 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java @@ -151,7 +151,7 @@ enum ColumnType { "PlainDecimal decimal(30)", "PlainNumeric numeric(30)"}; // junit test parameters: serverName, enclaveAttestationUrl, enclaveAttestationProtocol - static String[][] param = new String[(null == AbstractTest.enclaveServer ? 0 + static String[][] param = new String[(null == AbstractTest.enclaveServer ? 1 : AbstractTest.enclaveServer.length)][3]; /** From 38a6e98e0f172a0c5201c198050b99b1fb60fde3 Mon Sep 17 00:00:00 2001 From: Jeff Wasty Date: Wed, 26 Oct 2022 13:00:42 -0700 Subject: [PATCH 8/8] Fix AESetup (was changed for testing). --- .../com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java index a3d18c127..820fe5b0e 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java @@ -151,7 +151,7 @@ enum ColumnType { "PlainDecimal decimal(30)", "PlainNumeric numeric(30)"}; // junit test parameters: serverName, enclaveAttestationUrl, enclaveAttestationProtocol - static String[][] param = new String[(null == AbstractTest.enclaveServer ? 1 + static String[][] param = new String[(null == AbstractTest.enclaveServer ? 0 : AbstractTest.enclaveServer.length)][3]; /**