Skip to content

Commit

Permalink
Refactored AE tests to add new Enclave tests for testing AEv2 (#1166)
Browse files Browse the repository at this point in the history
  • Loading branch information
lilgreenbird authored Nov 13, 2019
1 parent 85e4e5f commit 2f339a4
Show file tree
Hide file tree
Showing 19 changed files with 1,895 additions and 605 deletions.
12 changes: 8 additions & 4 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
strategy:
matrix:
SQL-2019:
Target_SQL: 'SQL-2k19-01'
Target_SQL: 'HGS-2k19-01'
Ex_Groups: 'xSQLv15'
SQL-2012:
Target_SQL: 'SQL-2K12-SP3-1'
Expand Down Expand Up @@ -38,7 +38,8 @@ jobs:
displayName: 'Maven build jre13'
inputs:
mavenPomFile: 'pom.xml'
goals: 'clean -Dmssql_jdbc_test_connection_properties=jdbc:sqlserver://$(Target_SQL)$(server_domain);$(database);$(user);$(password); install -Pjre13 -DuserNTLM=$(userNTLM) -DpasswordNTLM=$(passwordNTLM) -DdomainNTLM=$(domainNTLM) -DexcludedGroups=$(Ex_Groups) -Dpkcs12_truststore_password=$(pkcs12_truststore_password) -Dpkcs12_truststore=$(pkcs12_truststore.secureFilePath)'
goals: 'clean -Dmssql_jdbc_test_connection_properties=jdbc:sqlserver://$(Target_SQL)$(server_domain);$(database);$(user);$(password); install -Pjre13 -DuserNTLM=$(userNTLM) -DpasswordNTLM=$(passwordNTLM) -DdomainNTLM=$(domainNTLM) -DexcludedGroups=$(Ex_Groups) -Dpkcs12_truststore_password=$(pkcs12_truststore_password) -Dpkcs12_truststore=$(pkcs12_truststore.secureFilePath)
-DapplicationClientID=$(applicationClientID) -DapplicationKey=$(applicationKey) -DkeyID=$(keyID) -DwindowsKeyPath=$(windowsKeyPath) -DenclaveAttestationUrl=$(enclaveAttestationUrl) -DenclaveAttestationProtocol=$(enclaveAttestationProtocol)'
testResultsFiles: '**/TEST-*.xml'
testRunTitle: 'Maven build jre13'
javaHomeOption: Path
Expand All @@ -47,7 +48,9 @@ jobs:
displayName: 'Maven build jre11'
inputs:
mavenPomFile: 'pom.xml'
goals: 'clean -Dmssql_jdbc_test_connection_properties=jdbc:sqlserver://$(Target_SQL)$(server_domain);$(database);$(user);$(password); install -Pjre11 -DuserNTLM=$(userNTLM) -DpasswordNTLM=$(passwordNTLM) -DdomainNTLM=$(domainNTLM) -DexcludedGroups=$(Ex_Groups) -Dpkcs12_truststore_password=$(pkcs12_truststore_password) -Dpkcs12_truststore=$(pkcs12_truststore.secureFilePath)'
goals: 'clean -Dmssql_jdbc_test_connection_properties=jdbc:sqlserver://$(Target_SQL)$(server_domain);$(database);$(user);$(password); install -Pjre11 -DuserNTLM=$(userNTLM) -DpasswordNTLM=$(passwordNTLM) -DdomainNTLM=$(domainNTLM) -DexcludedGroups=$(Ex_Groups) -Dpkcs12_truststore_password=$(pkcs12_truststore_password) -Dpkcs12_truststore=$(pkcs12_truststore.secureFilePath)
-DapplicationClientID=$(applicationClientID) -DapplicationKey=$(applicationKey) -DkeyID=$(keyID) -DwindowsKeyPath=$(windowsKeyPath) -DenclaveAttestationUrl=$(enclaveAttestationUrl) -DenclaveAttestationProtocol=$(enclaveAttestationProtocol)
'
testResultsFiles: '**/TEST-*.xml'
testRunTitle: 'Maven build jre11'
javaHomeOption: Path
Expand All @@ -56,7 +59,8 @@ jobs:
displayName: 'Maven build jre8'
inputs:
mavenPomFile: 'pom.xml'
goals: 'clean -Dmssql_jdbc_test_connection_properties=jdbc:sqlserver://$(Target_SQL)$(server_domain);$(database);$(user);$(password); install -Pjre8 -DuserNTLM=$(userNTLM) -DpasswordNTLM=$(passwordNTLM) -DdomainNTLM=$(domainNTLM) -DexcludedGroups=$(Ex_Groups) -Dpkcs12_truststore_password=$(pkcs12_truststore_password) -Dpkcs12_truststore=$(pkcs12_truststore.secureFilePath)'
goals: 'clean -Dmssql_jdbc_test_connection_properties=jdbc:sqlserver://$(Target_SQL)$(server_domain);$(database);$(user);$(password); install -Pjre8 -DuserNTLM=$(userNTLM) -DpasswordNTLM=$(passwordNTLM) -DdomainNTLM=$(domainNTLM) -DexcludedGroups=$(Ex_Groups) -Dpkcs12_truststore_password=$(pkcs12_truststore_password) -Dpkcs12_truststore=$(pkcs12_truststore.secureFilePath)
-DapplicationClientID=$(applicationClientID) -DapplicationKey=$(applicationKey) -DkeyID=$(keyID) -DwindowsKeyPath=$(windowsKeyPath) -DenclaveAttestationUrl=$(enclaveAttestationUrl) -DenclaveAttestationProtocol=$(enclaveAttestationProtocol)'
testResultsFiles: '**/TEST-*.xml'
testRunTitle: 'Maven build jre8'
javaHomeOption: Path
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
NTLM - - - - - - - For tests using NTLM Authentication mode (excluded by default)
reqExternalSetup - For tests requiring external setup (excluded by default)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Default testing enabled with SQL Server 2019 (SQLv14) -->
Default testing enabled with SQL Server 2019 (SQLv15) -->
<excludedGroups>xSQLv15, NTLM, reqExternalSetup</excludedGroups>

<!-- Use -preview for preview release, leave empty for official release.-->
Expand Down Expand Up @@ -491,7 +491,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.3</version>
<version>0.8.5</version>
<executions>
<execution>
<id>pre-test</id>
Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -6197,7 +6197,7 @@ void writeRPCReaderUnicode(String sName, Reader re, long reLength, boolean bOut,
void sendEnclavePackage(String sql, ArrayList<byte[]> enclaveCEKs) throws SQLServerException {
if (null != con && con.isAEv2()) {
if (null != sql && "" != sql && null != enclaveCEKs && 0 < enclaveCEKs.size() && con.enclaveEstablished()) {
byte[] b = con.generateEncalvePackage(sql, enclaveCEKs);
byte[] b = con.generateEnclavePackage(sql, enclaveCEKs);
if (null != b && 0 != b.length) {
this.writeShort((short) b.length);
this.writeBytes(b);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1473,25 +1473,20 @@ Connection connectInternal(Properties propsIn,
if (null != sPropValue) {
enclaveAttestationProtocol = sPropValue;
if (!AttestationProtocol.isValidAttestationProtocol(enclaveAttestationProtocol)) {
if (connectionlogger.isLoggable(Level.SEVERE)) {
connectionlogger.severe(toString() + " "
+ SQLServerException.getErrString("R_enclaveInvalidAttestationProtocol"));
}
throw new SQLServerException(SQLServerException.getErrString("R_enclaveInvalidAttestationProtocol"),
null);
}
}

// both enclaveAttestationUrl must be enclaveAttestationProtocol specified
// enclave requires columnEncryption=enabled, enclaveAttestationUrl and enclaveAttestationProtocol
if ((null != enclaveAttestationUrl && !enclaveAttestationUrl.isEmpty()
&& (null == enclaveAttestationProtocol || enclaveAttestationProtocol.isEmpty()))
|| (null != enclaveAttestationProtocol && !enclaveAttestationProtocol.isEmpty()
&& (null == enclaveAttestationUrl || enclaveAttestationUrl.isEmpty()))) {
if (connectionlogger.isLoggable(Level.SEVERE)) {
connectionlogger.severe(
toString() + " " + SQLServerException.getErrString("R_enclaveNoAttestationProtocol"));
}
throw new SQLServerException(SQLServerException.getErrString("R_enclaveNoAttestationProtocol"), null);
&& (null == enclaveAttestationUrl || enclaveAttestationUrl.isEmpty()))
|| (null != enclaveAttestationUrl && !enclaveAttestationUrl.isEmpty()
&& (null != enclaveAttestationProtocol || !enclaveAttestationProtocol.isEmpty())
&& (null == columnEncryptionSetting || !isColumnEncryptionSettingEnabled()))) {
throw new SQLServerException(SQLServerException.getErrString("R_enclavePropertiesError"), null);
}

sPropKey = SQLServerDriverStringProperty.KEY_STORE_AUTHENTICATION.toString();
Expand Down Expand Up @@ -6491,7 +6486,7 @@ boolean enclaveEstablished() {
return (null != enclaveProvider.getEnclaveSession());
}

byte[] generateEncalvePackage(String userSQL, ArrayList<byte[]> enclaveCEKs) throws SQLServerException {
byte[] generateEnclavePackage(String userSQL, ArrayList<byte[]> enclaveCEKs) throws SQLServerException {
return (enclaveCEKs.size() > 0) ? enclaveProvider.getEnclavePackage(userSQL, enclaveCEKs) : null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,7 @@ private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServer
// cekEntry will be null if none of the parameters are encrypted.
if ((null != cekEntry) && (cekList.size() < cekOrdinal)) {
MessageFormat form = new MessageFormat(
SQLServerException.getErrString("R_InvalidEncryptionKeyOridnal"));
SQLServerException.getErrString("R_InvalidEncryptionKeyOrdinal"));
Object[] msgArgs = {cekOrdinal, cekEntry.getSize()};
throw new SQLServerException(this, form.format(msgArgs), null, 0, false);
}
Expand Down Expand Up @@ -2732,7 +2732,7 @@ final void doExecutePreparedStatementBatch(PrepStmtBatchExecCmd batchCommand) th
boolean hasExistingTypeDefinitions = preparedTypeDefinitions != null;
boolean hasNewTypeDefinitions = buildPreparedStrings(batchParam, false);

if (!isInternalEncryptionQuery && connection.isAEv2()) {
if ((0 == numBatchesExecuted) && !isInternalEncryptionQuery && connection.isAEv2()) {
this.enclaveCEKs = connection.initEnclaveParameters(preparedSQL, preparedTypeDefinitions, batchParam,
parameterNames);
encryptionMetadataIsRetrieved = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ protected Object[][] getContents() {
{"R_unsupportedEncoding", "The encoding {0} is not supported."},
{"R_UnexpectedDescribeParamFormat",
"Internal error. The format of the resultset returned by sp_describe_parameter_encryption is invalid. One of the resultsets is missing."},
{"R_InvalidEncryptionKeyOridnal",
{"R_InvalidEncryptionKeyOrdinal",
"Internal error. The referenced column encryption key ordinal \"{0}\" is missing in the encryption metadata returned by sp_describe_parameter_encryption. Max ordinal is \"{1}\"."},
{"R_MissingParamEncryptionMetadata",
"Internal error. Metadata for some parameters in statement or procedure \"{0}\" is missing in the resultset returned by sp_describe_parameter_encryption."},
Expand Down Expand Up @@ -598,8 +598,8 @@ protected Object[][] getContents() {
"An error occurred when matching VALUES list to table columns. Please verify SQL syntax."},
{"R_invalidValuesList", "An error occurred when reading VALUES list. Please verify SQL syntax."},
{"R_enclaveNotSupported", "The SQL Server instance does not support enclave based computations."},
{"R_enclaveNoAttestationProtocol",
"The \"enclaveAttestationProtocol\" connection property must be specified with \"enclaveAttestationUrl\"."},
{"R_enclavePropertiesError",
"The \"columnEncryptionSetting\" connection property must be enabled, along with valid \"enclaveAttestationUrl\" and \"enclaveAttestationProtocol\" connection properties when enabling Always Encrypted with secrure enclaves ."},
{"R_enclaveInvalidAttestationProtocol", "The \"enclaveAttestationProtocol\" is invalid."},
{"R_enclaveTypeInvalid", "The enclave type {0} is invalid or not supported by the driver."},
{"R_attestationUrlInvalid", "Unable to attest enclave specified by {0}."},
Expand All @@ -611,6 +611,8 @@ protected Object[][] getContents() {
"More bytes from the server were received than expected when parsing Enclave PK."},
{"R_MalformedECDHPublicKey", "The ECDH public key from the server must be 104 bits in length."},
{"R_MalformedECDHHeader", "Unexpected values for ECDH public key header from the server."},
{"R_HealthCertError",
" Enclave Attestation failed, could not retrieve health report certificate provided in the enclave: {0}."},
{"R_InvalidHealthCert",
" Enclave Attestation failed, the health report certificate provided in the enclave was not signed by the HGS."},
{"R_InvalidSignedStatement",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public byte[] getEnclavePackage(String userSQL, ArrayList<byte[]> enclaveCEKs) t
SQLServerEncryptionType.Randomized, (byte) 0x1);
enclavePackage.writeBytes(algo.encryptData(keys.toByteArray()));
return enclavePackage.toByteArray();
} catch (GeneralSecurityException | SQLServerException e) {
} catch (GeneralSecurityException e) {
SQLServerException.makeFromDriverError(null, this, e.getLocalizedMessage(), "0", false);
}
}
Expand Down Expand Up @@ -251,7 +251,7 @@ private ArrayList<byte[]> describeParameterEncryption(SQLServerConnection connec
// cekEntry will be null if none of the parameters are encrypted.
if ((null != cekEntry) && (cekList.size() < cekOrdinal)) {
MessageFormat form = new MessageFormat(
SQLServerException.getErrString("R_InvalidEncryptionKeyOridnal"));
SQLServerException.getErrString("R_InvalidEncryptionKeyOrdinal"));
Object[] msgArgs = {cekOrdinal, cekEntry.getSize()};
throw new SQLServerException(this, form.format(msgArgs), null, 0, false);
}
Expand Down Expand Up @@ -362,17 +362,19 @@ byte[] getBytes() {
}

byte[] createSessionSecret(byte[] serverResponse) throws GeneralSecurityException, SQLServerException {
if (serverResponse.length != ENCLAVE_LENGTH) {
if (null == serverResponse || serverResponse.length != ENCLAVE_LENGTH) {
SQLServerException.makeFromDriverError(null, this,
SQLServerResource.getResource("R_MalformedECDHPublicKey"), "0", false);
}
ByteBuffer sr = ByteBuffer.wrap(serverResponse);
byte[] magic = new byte[8];
sr.get(magic);

if (!Arrays.equals(magic, ECDH_MAGIC)) {
SQLServerException.makeFromDriverError(null, this, SQLServerResource.getResource("R_MalformedECDHHeader"),
"0", false);
}

byte[] x = new byte[48];
byte[] y = new byte[48];
sr.get(x);
Expand Down Expand Up @@ -431,61 +433,69 @@ class AttestationResponse {
* DH Public Key - DHPKsize bytes
* DH Public Key Signature - DHPKSsize bytes
*/
ByteBuffer response = ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN);
this.totalSize = response.getInt();
this.identitySize = response.getInt();
this.healthReportSize = response.getInt();
this.enclaveReportSize = response.getInt();

enclavePK = new byte[identitySize];
healthReportCertificate = new byte[healthReportSize];
enclaveReportPackage = new byte[enclaveReportSize];

response.get(enclavePK, 0, identitySize);
response.get(healthReportCertificate, 0, healthReportSize);
response.get(enclaveReportPackage, 0, enclaveReportSize);

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);
ByteBuffer response = (null != b) ? ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN) : null;
if (null != response) {
this.totalSize = response.getInt();
this.identitySize = response.getInt();
this.healthReportSize = response.getInt();
this.enclaveReportSize = response.getInt();

enclavePK = new byte[identitySize];
healthReportCertificate = new byte[healthReportSize];
enclaveReportPackage = new byte[enclaveReportSize];

response.get(enclavePK, 0, identitySize);
response.get(healthReportCertificate, 0, healthReportSize);
response.get(enclaveReportPackage, 0, enclaveReportSize);

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);
}

// Create a X.509 certificate from the bytes
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
healthCert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(healthReportCertificate));
} catch (CertificateException ce) {
SQLServerException.makeFromDriverError(null, this, ce.getLocalizedMessage(), "0", false);
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_HealthCertError"));
Object[] msgArgs = {ce.getLocalizedMessage()};
SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, true);
}
}

@SuppressWarnings("unchecked")
void validateCert(byte[] b) throws SQLServerException {
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Collection<X509Certificate> certs = (Collection<X509Certificate>) cf
.generateCertificates(new ByteArrayInputStream(b));
for (X509Certificate cert : certs) {
try {
healthCert.verify(cert.getPublicKey());
return;
} catch (SignatureException e) {
// Doesn't match, but continue looping through the rest of the certificates
if (null != b) {
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Collection<X509Certificate> certs = (Collection<X509Certificate>) cf
.generateCertificates(new ByteArrayInputStream(b));
for (X509Certificate cert : certs) {
try {
healthCert.verify(cert.getPublicKey());
return;
} catch (SignatureException e) {
// Doesn't match, but continue looping through the rest of the certificates
}
}
} catch (GeneralSecurityException e) {
SQLServerException.makeFromDriverError(null, this, e.getLocalizedMessage(), "0", false);
}
} catch (GeneralSecurityException e) {
SQLServerException.makeFromDriverError(null, this, e.getLocalizedMessage(), "0", false);
}

SQLServerException.makeFromDriverError(null, this, SQLServerResource.getResource("R_InvalidHealthCert"), "0",
false);
}
Expand Down
Loading

0 comments on commit 2f339a4

Please sign in to comment.