Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature | Added support for Always Encrypted with Secure Enclaves #1155

Merged
merged 97 commits into from
Oct 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
55d0840
add enclaveAttestationUrl property
lilgreenbird Sep 4, 2019
6f543bf
Merge pull request #1140 from lilgreenbird/aev2
rene-ye Sep 5, 2019
bd214ad
enclaveType
lilgreenbird Sep 6, 2019
0557d1a
enclaveType (#1141)
lilgreenbird Sep 6, 2019
5b0fee0
added some junit tests and attestationProtocol property
lilgreenbird Sep 6, 2019
22fa9bb
resovled conflicts
lilgreenbird Sep 6, 2019
6cb3994
Add | Enclave STuff
rene-ye Sep 12, 2019
ae19d23
Merge branch 'aev2' of https://github.com/rene-ye/mssql-jdbc into aev2
lilgreenbird Sep 12, 2019
4bc018f
asdf
rene-ye Sep 12, 2019
7aceb50
Merge branch 'aev2' of https://github.com/rene-ye/mssql-jdbc into aev2
lilgreenbird Sep 12, 2019
0898459
merged with Rene
lilgreenbird Sep 12, 2019
ca3b4ed
asd
rene-ye Sep 13, 2019
793eb38
Merge branch 'aev2' of https://github.com/rene-ye/mssql-jdbc into aev2
lilgreenbird Sep 13, 2019
72e4daa
asdf
rene-ye Sep 13, 2019
7a81056
merged
lilgreenbird Sep 13, 2019
bd5ddca
fix server stuff
rene-ye Sep 13, 2019
0816100
save work
lilgreenbird Sep 23, 2019
256aae7
parse json
rene-ye Sep 23, 2019
d619849
Fix ECDH Key
rene-ye Sep 24, 2019
6333f79
fixed akv verify
lilgreenbird Sep 24, 2019
b78470f
merged with rene
lilgreenbird Sep 24, 2019
aa11348
Add | generate session key
rene-ye Sep 26, 2019
f37606f
merged with Rene
lilgreenbird Sep 26, 2019
8f22a1d
Change some array stuff
rene-ye Sep 26, 2019
3643687
poosh
rene-ye Oct 2, 2019
0e2689c
AEv2 works
rene-ye Oct 3, 2019
ee4e9a9
Remove print
rene-ye Oct 4, 2019
060dbfa
Merge branch 'dev' of https://github.com/Microsoft/mssql-jdbc into aev2
rene-ye Oct 4, 2019
4c23d7e
Push | Tests
rene-ye Oct 4, 2019
d675d9c
Rich Query works
rene-ye Oct 7, 2019
d0126ca
Fix Encryption stuff?
rene-ye Oct 7, 2019
8284baf
Fix other commands
rene-ye Oct 8, 2019
65040d6
Fix some datatype issues
rene-ye Oct 8, 2019
867dff8
Turn AEv1 back on
rene-ye Oct 8, 2019
327e494
Change some if-else logic
rene-ye Oct 8, 2019
51e88be
Fix for limit test
rene-ye Oct 8, 2019
3642e09
Some code cleanup
rene-ye Oct 8, 2019
1239bb6
added new tests
lilgreenbird Oct 9, 2019
95fcd30
fixed numeric test
lilgreenbird Oct 9, 2019
23b54bc
update
lilgreenbird Oct 9, 2019
2100c8a
big changes
rene-ye Oct 9, 2019
d6890ed
removed vi swap file
lilgreenbird Oct 9, 2019
10d2afe
Merge pull request #49 from lilgreenbird/aev2rene
lilgreenbird Oct 9, 2019
01e95b4
Fix stackoverflow issue
rene-ye Oct 9, 2019
0d9a895
Merge branch 'aev2' of https://github.com/rene-ye/mssql-jdbc into aev2
rene-ye Oct 9, 2019
c34d11a
remove an underused function
rene-ye Oct 9, 2019
43015e9
comments
rene-ye Oct 9, 2019
bf984d9
added checks for keystore properties
lilgreenbird Oct 9, 2019
31fe485
Merge pull request #50 from lilgreenbird/aev2rene
lilgreenbird Oct 9, 2019
8b16116
Code Cleanup
rene-ye Oct 9, 2019
fbe8a8f
Remove debug line
rene-ye Oct 9, 2019
48d0ecd
split tests to aev1 and v2
lilgreenbird Oct 10, 2019
9c2669d
do check
rene-ye Oct 10, 2019
0aec438
added getColumnEncryptionKeyCacheTtl
lilgreenbird Oct 10, 2019
ef36102
Fix DHPublicKey verification
rene-ye Oct 10, 2019
b633031
minor cleanup
rene-ye Oct 10, 2019
3c71d8e
added enclaveAttestationProtocol and fixed tests
lilgreenbird Oct 10, 2019
5786365
Merge branch 'aev2' into aev2rene
rene-ye Oct 10, 2019
47476bf
Merge pull request #51 from lilgreenbird/aev2rene
rene-ye Oct 10, 2019
d151003
fixed spelling
lilgreenbird Oct 10, 2019
b86fdd8
Merge pull request #52 from lilgreenbird/aev2rene
lilgreenbird Oct 10, 2019
aa5629c
spelling fix
lilgreenbird Oct 10, 2019
55c900a
Merge pull request #53 from lilgreenbird/aev2rene
lilgreenbird Oct 10, 2019
3bdd870
fix spelling
rene-ye Oct 10, 2019
530e7b5
added attestationProtocol to datasource
lilgreenbird Oct 11, 2019
20322be
Update ISQLServerDataSource.java
rene-ye Oct 11, 2019
ae93f86
Update SQLServerDataSource.java
rene-ye Oct 11, 2019
4946b6d
Merge pull request #54 from lilgreenbird/aev2rene
rene-ye Oct 11, 2019
e617844
fixed typo
lilgreenbird Oct 11, 2019
f972973
Merge branch 'aev2' of https://github.com/rene-ye/mssql-jdbc into aev…
lilgreenbird Oct 11, 2019
626bd9a
fix typo
rene-ye Oct 11, 2019
4bb6192
Remove package for connectionCommand
rene-ye Oct 11, 2019
c2064e1
fixed null ptr
lilgreenbird Oct 11, 2019
7b9360f
null ptr check
lilgreenbird Oct 11, 2019
8123e36
Update src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java
ulvii Oct 11, 2019
5c9fdf1
Update src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java
ulvii Oct 11, 2019
f4ce44f
Update src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java
ulvii Oct 11, 2019
cffe8c1
Update src/main/java/com/microsoft/sqlserver/jdbc/SQLServerVSMEnclave…
ulvii Oct 11, 2019
91c30d1
Update src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSourc…
ulvii Oct 12, 2019
120ac97
Update src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSourc…
ulvii Oct 12, 2019
ea52cd0
Update src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSourc…
ulvii Oct 12, 2019
ffa25fe
Update src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSourc…
ulvii Oct 12, 2019
3577916
Update src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncr…
ulvii Oct 12, 2019
95b5fff
Merge branch 'aev2' of https://github.com/rene-ye/mssql-jdbc into aev…
lilgreenbird Oct 12, 2019
6298647
review updates
lilgreenbird Oct 12, 2019
7748999
Merge pull request #55 from lilgreenbird/aev2rene
lilgreenbird Oct 12, 2019
08afe4c
more review updates
lilgreenbird Oct 14, 2019
4186fb4
Fix batch executes and address comments
rene-ye Oct 14, 2019
f70d686
fixed getting wrong keystore
lilgreenbird Oct 14, 2019
fdb6f04
null check
lilgreenbird Oct 14, 2019
07d34ed
Merge pull request #56 from lilgreenbird/aev2rene
lilgreenbird Oct 14, 2019
5563953
Add javadoc comments
rene-ye Oct 14, 2019
8962adf
Restore constant
rene-ye Oct 14, 2019
66a9e54
Fix regression
rene-ye Oct 14, 2019
9c20e00
Revert AEv1 changes
rene-ye Oct 15, 2019
2fa9baa
minor changes
lilgreenbird Oct 15, 2019
6a222cd
Merge pull request #57 from lilgreenbird/aev2rene
lilgreenbird Oct 15, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/main/java/com/microsoft/sqlserver/jdbc/AE.java
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,9 @@ enum DescribeParameterEncryptionResultSet1 {
EncryptedKey,
ProviderName,
KeyPath,
KeyEncryptionAlgorithm;
KeyEncryptionAlgorithm,
IsRequestedByEnclave,
EnclaveCMKSignature;

int value() {
// Column indexing starts from 1;
Expand All @@ -266,5 +268,15 @@ int value() {
// Column indexing starts from 1;
return ordinal() + 1;
}
}

enum ColumnEncryptionVersion {
AE_NotSupported,
AE_v1,
AE_v2;

int value() {
// Column indexing starts from 1;
return ordinal() + 1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,7 @@ private static native FedAuthDllInfo ADALGetAccessTokenForWindowsIntegrated(Stri

static native byte[] DecryptColumnEncryptionKey(String masterKeyPath, String encryptionAlgorithm,
byte[] encryptedColumnEncryptionKey) throws DLLException;

static native boolean VerifyColumnMasterKeyMetadata(String keyPath, boolean allowEnclaveComputations,
byte[] signature) throws DLLException;
}
28 changes: 26 additions & 2 deletions src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.text.MessageFormat;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
Expand Down Expand Up @@ -113,7 +114,9 @@ final class TDS {
// AE constants
// 0x03 is for x_eFeatureExtensionId_Rcs
static final byte TDS_FEATURE_EXT_AE = 0x04;
static final byte MAX_SUPPORTED_TCE_VERSION = 0x01; // max version
static final byte COLUMNENCRYPTION_NOT_SUPPORTED = 0x00; // column encryption not supported
static final byte COLUMNENCRYPTION_VERSION1 = 0x01; // column encryption without enclave
static final byte COLUMNENCRYPTION_VERSION2 = 0x02; // column encryption with enclave
static final int CUSTOM_CIPHER_ALGORITHM_ID = 0; // max version
// 0x06 is for x_eFeatureExtensionId_LoginToken
// 0x07 is for x_eFeatureExtensionId_ClientSideTelemetry
Expand Down Expand Up @@ -3701,8 +3704,9 @@ void writeBytes(byte[] value, int offset, int length) throws SQLServerException
int bytesWritten = 0;
int bytesToWrite;

if (logger.isLoggable(Level.FINEST))
if (logger.isLoggable(Level.FINEST)) {
logger.finest(toString() + " Writing " + length + " bytes");
}

while ((bytesToWrite = length - bytesWritten) > 0) {
if (0 == stagingBuffer.remaining())
Expand Down Expand Up @@ -6189,6 +6193,22 @@ void writeRPCReaderUnicode(String sName, Reader re, long reLength, boolean bOut,
// Write the data
writeReader(re, reLength, usePLP);
}

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);
if (null != b && 0 != b.length) {
this.writeShort((short) b.length);
this.writeBytes(b);
} else {
this.writeShort((short) 0);
}
} else {
this.writeShort((short) 0);
}
}
}
}


Expand Down Expand Up @@ -6284,6 +6304,7 @@ final SQLServerConnection getConnection() {
private boolean useColumnEncryption = false;
private boolean serverSupportsColumnEncryption = false;
private boolean serverSupportsDataClassification = false;
private ColumnEncryptionVersion columnEncryptionVersion;

private final byte valueBytes[] = new byte[256];

Expand All @@ -6308,6 +6329,7 @@ private static int nextReaderID() {
useColumnEncryption = true;
}
serverSupportsColumnEncryption = con.getServerSupportsColumnEncryption();
columnEncryptionVersion = con.getServerColumnEncryptionVersion();
serverSupportsDataClassification = con.getServerSupportsDataClassification();
}

Expand Down Expand Up @@ -7162,6 +7184,8 @@ final boolean readingResponse() {
return readingResponse;
}

protected ArrayList<byte[]> enclaveCEKs;

/**
* Creates this command with an optional timeout.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,13 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
*/
void setKeyVaultProviderClientKey(String keyVaultProviderClientKey);

/**
* Returns the value for the connection property 'domain'.
*
* @return 'domain' property value
*/
String getDomain();

/**
* Sets the 'domain' connection property used for NTLM Authentication.
*
Expand All @@ -852,13 +859,6 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
*/
void setDomain(String domain);

/**
* Returns the value for the connection property 'domain'.
*
* @return 'domain' property value
*/
String getDomain();

/**
* Returns the current flag value for useFmtOnly.
*
Expand All @@ -873,4 +873,35 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
* boolean value for 'useFmtOnly'.
*/
void setUseFmtOnly(boolean useFmtOnly);

/**
* Returns the enclave attestation URL used in Always Encrypted with Secure Enclaves.
*
* @return enclave attestation URL.
*/
String getEnclaveAttestationUrl();

/**
* Sets the enclave attestation URL used in Always Encrypted with Secure Enclaves.
*
* @param url
* Enclave attestation URL.
*/
void setEnclaveAttestationUrl(String url);

/**
* Returns the enclave attestation protocol used in Always Encrypted with Secure Enclaves.
*
* @return Enclave attestation protocol.
*/
String getEnclaveAttestationProtocol();

/**
* Sets the enclave attestation protocol to be used in Always Encrypted with Secure Enclaves.
*
* @param protocol
* Enclave attestation protocol.
*/
void setEnclaveAttestationProtocol(String protocol);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made
* available under the terms of the MIT License. See the LICENSE file in the project root for more information.
*/

package com.microsoft.sqlserver.jdbc;
lilgreenbird marked this conversation as resolved.
Show resolved Hide resolved

import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;

/**
*
* Provides an interface to create an Enclave Session
*
*/
public interface ISQLServerEnclaveProvider {
byte[] getEnclavePackage(String userSQL, ArrayList<byte[]> enclaveCEKs) throws SQLServerException;
lilgreenbird marked this conversation as resolved.
Show resolved Hide resolved

/**
* Returns the attestation parameters
* @param createNewParameters
* indicates whether to create new parameters
* @param url
* attestation url
* @throws SQLServerException
* when an error occurs.
*/
void getAttestationParameters(boolean createNewParameters, String url) throws SQLServerException;

/**
* Creates the enclave session
*
* @param connection
* connection
* @param userSql
* user sql
* @param preparedTypeDefinitions
* preparedTypeDefinitions
* @param params
* params
* @param parameterNames
* parameterNames
* @return
* list of enclave requested CEKs
* @throws SQLServerException
* when an error occurs.
*/
ArrayList<byte[]> createEnclaveSession(SQLServerConnection connection, String userSql,
String preparedTypeDefinitions, Parameter[] params,
ArrayList<String> parameterNames) throws SQLServerException;

/**
* Invalidates an enclave session
*/
void invalidateEnclaveSession();

/**
* Returns the enclave session
* @return
* the enclave session
*/
EnclaveSession getEnclaveSession();
}


abstract class BaseAttestationRequest {
protected PrivateKey privateKey;

byte[] getBytes() {
return null;
};
}


class EnclaveSession {
private byte[] sessionID;
private AtomicInteger counter;
private byte[] sessionSecret;

EnclaveSession(byte[] cs, byte[] b) {
sessionID = cs;
sessionSecret = b;
counter = new AtomicInteger(0);
}

byte[] getSessionID() {
return sessionID;
}

byte[] getSessionSecret() {
return sessionSecret;
}

long getCounter() {
return counter.getAndIncrement();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ private static byte[] decryptRSAOAEP(byte[] cipherText,

}

private static boolean verifyRSASignature(byte[] hash, byte[] signature, X509Certificate certificate,
static boolean verifyRSASignature(byte[] hash, byte[] signature, X509Certificate certificate,
String masterKeyPath) throws SQLServerException {
Signature signVerify;
boolean verificationSuccess = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1544,13 +1544,14 @@ private TDSWriter sendBulkCopyCommand(TDSCommand command) throws SQLServerExcept
// Create and send the initial command for bulk copy ("INSERT BULK ...").
TDSWriter tdsWriter = command.startRequest(TDS.PKT_QUERY);
String bulkCmd = createInsertBulkCommand(tdsWriter);
tdsWriter.sendEnclavePackage(null, null);
rene-ye marked this conversation as resolved.
Show resolved Hide resolved
tdsWriter.writeString(bulkCmd);
TDSParser.parse(command.startResponse(), command.getLogContext());

// Send the bulk data. This is the BulkLoadBCP TDS stream.
tdsWriter = command.startRequest(TDS.PKT_BULK);

// Write the COLUMNMETADATA token in the stream.

writeColumnMetaData(tdsWriter);

return tdsWriter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,19 +448,24 @@ private void ValidateNonEmptyAKVPath(String masterKeyPath) throws SQLServerExcep
URI parsedUri = null;
try {
parsedUri = new URI(masterKeyPath);

// A valid URI.
// Check if it is pointing to a trusted endpoint.
String host = parsedUri.getHost();
if (null != host) {
host = host.toLowerCase(Locale.ENGLISH);
}
for (final String endpoint : azureTrustedEndpoints) {
if (null != host && host.endsWith(endpoint)) {
return;
}
}
} catch (URISyntaxException e) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AKVURLInvalid"));
Object[] msgArgs = {masterKeyPath};
throw new SQLServerException(form.format(msgArgs), null, 0, e);
}

// A valid URI.
// Check if it is pointing to a trusted endpoint.
for (final String endpoint : azureTrustedEndpoints) {
if (parsedUri.getHost().toLowerCase(Locale.ENGLISH).endsWith(endpoint)) {
return;
}
}
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AKVMasterKeyPathInvalid"));
Object[] msgArgs = {masterKeyPath};
throw new SQLServerException(null, form.format(msgArgs), null, 0, false);
Expand Down Expand Up @@ -590,4 +595,37 @@ private int getAKVKeySize(String masterKeyPath) throws SQLServerException {

return retrievedKey.key().n().length;
}

@Override
public boolean verifyColumnMasterKeyMetadata(String masterKeyPath, boolean allowEnclaveComputations,
byte[] signature) throws SQLServerException {
if (!allowEnclaveComputations)
return false;

KeyStoreProviderCommon.validateNonEmptyMasterKeyPath(masterKeyPath);

try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(name.toLowerCase().getBytes(java.nio.charset.StandardCharsets.UTF_16LE));
md.update(masterKeyPath.toLowerCase().getBytes(java.nio.charset.StandardCharsets.UTF_16LE));
// value of allowEnclaveComputations is always true here
md.update("true".getBytes(java.nio.charset.StandardCharsets.UTF_16LE));

byte[] dataToVerify = md.digest();
if (null == dataToVerify) {
throw new SQLServerException(SQLServerException.getErrString("R_HashNull"), null);
}

// Sign the hash
byte[] signedHash = AzureKeyVaultSignHashedData(dataToVerify, masterKeyPath);
if (null == signedHash) {
throw new SQLServerException(SQLServerException.getErrString("R_SignedHashLengthError"), null);
}

// Validate the signature
return AzureKeyVaultVerifySignature(dataToVerify, signature, masterKeyPath);
} catch (NoSuchAlgorithmException e) {
throw new SQLServerException(SQLServerException.getErrString("R_NoSHA256Algorithm"), e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,15 @@ public byte[] decryptColumnEncryptionKey(String masterKeyPath, String encryption
"decryptColumnEncryptionKey", "Finished decrypting Column Encryption Key.");
return plainCek;
}

@Override
public boolean verifyColumnMasterKeyMetadata(String masterKeyPath, boolean allowEnclaveComputations,
byte[] signature) throws SQLServerException {
try {
return AuthenticationJNI.VerifyColumnMasterKeyMetadata(masterKeyPath, allowEnclaveComputations, signature);
} catch (DLLException e) {
DLLException.buildException(e.GetErrCode(), e.GetParam1(), e.GetParam2(), e.GetParam3());
return false;
}
}
}
Loading