This commit is contained in:
David Puglielli 2018-05-18 12:24:37 -07:00
Родитель 757a84fd4c
Коммит 10ea9286d8
5 изменённых файлов: 167 добавлений и 160 удалений

Просмотреть файл

@ -940,83 +940,83 @@ void determine_server_version( _Inout_ sqlsrv_conn* conn TSRMLS_DC )
conn->server_version = version_major;
}
void load_azure_key_vault( _Inout_ sqlsrv_conn* conn TSRMLS_DC )
void load_azure_key_vault(_Inout_ sqlsrv_conn* conn TSRMLS_DC)
{
// If column encryption is not enabled simply do nothing. Otherwise, check if Azure Key Vault
// is required for encryption or decryption. Note, in order to load and configure Azure Key Vault,
// all fields in conn->ce_option must be defined.
if ( ! conn->ce_option.enabled || ! conn->ce_option.akv_required )
return;
CHECK_CUSTOM_ERROR( conn->ce_option.akv_mode == -1, conn, SQLSRV_ERROR_AKV_AUTH_MISSING) {
throw core::CoreException();
}
// If column encryption is not enabled simply do nothing. Otherwise, check if Azure Key Vault
// is required for encryption or decryption. Note, in order to load and configure Azure Key Vault,
// all fields in conn->ce_option must be defined.
if (!conn->ce_option.enabled || !conn->ce_option.akv_required)
return;
CHECK_CUSTOM_ERROR( conn->ce_option.akv_id == NULL, conn, SQLSRV_ERROR_AKV_NAME_MISSING) {
throw core::CoreException();
}
CHECK_CUSTOM_ERROR(conn->ce_option.akv_mode == -1, conn, SQLSRV_ERROR_AKV_AUTH_MISSING) {
throw core::CoreException();
}
CHECK_CUSTOM_ERROR( conn->ce_option.akv_secret == NULL, conn, SQLSRV_ERROR_AKV_SECRET_MISSING) {
throw core::CoreException();
}
char *akv_id = Z_STRVAL_P( conn->ce_option.akv_id );
char *akv_secret = Z_STRVAL_P( conn->ce_option.akv_secret );
unsigned int id_len = static_cast<unsigned int>( Z_STRLEN_P( conn->ce_option.akv_id ));
unsigned int key_size = static_cast<unsigned int>( Z_STRLEN_P( conn->ce_option.akv_secret ));
CHECK_CUSTOM_ERROR(conn->ce_option.akv_id == NULL, conn, SQLSRV_ERROR_AKV_NAME_MISSING) {
throw core::CoreException();
}
configure_azure_key_vault( conn, AKV_CONFIG_FLAGS, conn->ce_option.akv_mode, 0 );
configure_azure_key_vault( conn, AKV_CONFIG_PRINCIPALID, akv_id, id_len );
configure_azure_key_vault( conn, AKV_CONFIG_AUTHSECRET, akv_secret, key_size );
CHECK_CUSTOM_ERROR(conn->ce_option.akv_secret == NULL, conn, SQLSRV_ERROR_AKV_SECRET_MISSING) {
throw core::CoreException();
}
char *akv_id = Z_STRVAL_P(conn->ce_option.akv_id);
char *akv_secret = Z_STRVAL_P(conn->ce_option.akv_secret);
unsigned int id_len = static_cast<unsigned int>(Z_STRLEN_P(conn->ce_option.akv_id));
unsigned int key_size = static_cast<unsigned int>(Z_STRLEN_P(conn->ce_option.akv_secret));
configure_azure_key_vault(conn, AKV_CONFIG_FLAGS, conn->ce_option.akv_mode, 0);
configure_azure_key_vault(conn, AKV_CONFIG_PRINCIPALID, akv_id, id_len);
configure_azure_key_vault(conn, AKV_CONFIG_AUTHSECRET, akv_secret, key_size);
}
void configure_azure_key_vault( sqlsrv_conn* conn, BYTE config_attr, const DWORD config_value, size_t key_size )
void configure_azure_key_vault(sqlsrv_conn* conn, BYTE config_attr, const DWORD config_value, size_t key_size)
{
BYTE akv_data[sizeof( CEKEYSTOREDATA ) + sizeof(DWORD) + 1 ];
CEKEYSTOREDATA *pData = reinterpret_cast<CEKEYSTOREDATA*>( akv_data );
char akv_name[] = "AZURE_KEY_VAULT";
unsigned int name_len = 15;
unsigned int wname_len = 0;
sqlsrv_malloc_auto_ptr<SQLWCHAR> wakv_name;
wakv_name = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, akv_name, name_len, &wname_len );
BYTE akv_data[sizeof(CEKEYSTOREDATA) + sizeof(DWORD) + 1];
CEKEYSTOREDATA *pData = reinterpret_cast<CEKEYSTOREDATA*>(akv_data);
CHECK_CUSTOM_ERROR( wakv_name == 0, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE ) {
throw core::CoreException();
}
char akv_name[] = "AZURE_KEY_VAULT";
unsigned int name_len = 15;
unsigned int wname_len = 0;
sqlsrv_malloc_auto_ptr<SQLWCHAR> wakv_name;
wakv_name = utf16_string_from_mbcs_string(SQLSRV_ENCODING_UTF8, akv_name, name_len, &wname_len);
pData->name = (wchar_t *) wakv_name.get();
pData->data[0] = config_attr;
pData->dataSize = sizeof(config_attr) + sizeof(config_value);
*reinterpret_cast<DWORD*>(&pData->data[1]) = config_value;
core::SQLSetConnectAttr( conn, SQL_COPT_SS_CEKEYSTOREDATA, reinterpret_cast<SQLPOINTER>(pData), SQL_IS_POINTER );
CHECK_CUSTOM_ERROR(wakv_name == 0, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE) {
throw core::CoreException();
}
pData->name = (wchar_t *)wakv_name.get();
pData->data[0] = config_attr;
pData->dataSize = sizeof(config_attr) + sizeof(config_value);
*reinterpret_cast<DWORD*>(&pData->data[1]) = config_value;
core::SQLSetConnectAttr(conn, SQL_COPT_SS_CEKEYSTOREDATA, reinterpret_cast<SQLPOINTER>(pData), SQL_IS_POINTER);
}
void configure_azure_key_vault( sqlsrv_conn* conn, BYTE config_attr, const char* config_value, size_t key_size )
void configure_azure_key_vault(sqlsrv_conn* conn, BYTE config_attr, const char* config_value, size_t key_size)
{
BYTE akv_data[sizeof( CEKEYSTOREDATA ) + MAX_CE_NAME_LEN ];
CEKEYSTOREDATA *pData = reinterpret_cast<CEKEYSTOREDATA*>( akv_data );
BYTE akv_data[sizeof(CEKEYSTOREDATA) + MAX_CE_NAME_LEN];
CEKEYSTOREDATA *pData = reinterpret_cast<CEKEYSTOREDATA*>(akv_data);
char akv_name[] = "AZURE_KEY_VAULT";
unsigned int name_len = 15;
unsigned int wname_len = 0;
sqlsrv_malloc_auto_ptr<SQLWCHAR> wakv_name;
wakv_name = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, akv_name, name_len, &wname_len );
char akv_name[] = "AZURE_KEY_VAULT";
unsigned int name_len = 15;
unsigned int wname_len = 0;
sqlsrv_malloc_auto_ptr<SQLWCHAR> wakv_name;
wakv_name = utf16_string_from_mbcs_string(SQLSRV_ENCODING_UTF8, akv_name, name_len, &wname_len);
CHECK_CUSTOM_ERROR( wakv_name == 0, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE ) {
throw core::CoreException();
}
CHECK_CUSTOM_ERROR(wakv_name == 0, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE) {
throw core::CoreException();
}
pData->name = (wchar_t *) wakv_name.get();
pData->data[0] = config_attr;
pData->dataSize = 1+key_size;
pData->name = (wchar_t *)wakv_name.get();
memcpy_s( pData->data+1, key_size * sizeof( char ) , config_value, key_size );
core::SQLSetConnectAttr( conn, SQL_COPT_SS_CEKEYSTOREDATA, reinterpret_cast<SQLPOINTER>(pData), SQL_IS_POINTER );
pData->data[0] = config_attr;
pData->dataSize = 1 + key_size;
memcpy_s(pData->data + 1, key_size * sizeof(char), config_value, key_size);
core::SQLSetConnectAttr(conn, SQL_COPT_SS_CEKEYSTOREDATA, reinterpret_cast<SQLPOINTER>(pData), SQL_IS_POINTER);
}
void common_conn_str_append_func( _In_z_ const char* odbc_name, _In_reads_(val_len) const char* val, _Inout_ size_t val_len, _Inout_ std::string& conn_str TSRMLS_DC )

Просмотреть файл

@ -1,12 +1,11 @@
--TEST--
Test connection keywords and credentials for Azure Key Vault for Always Encrypted.
Test connection keywords for Azure Key Vault for Always Encrypted.
--SKIPIF--
<?php require('skipif.inc'); ?>
--FILE--
<?php
// Skip for 32-bit PHP, as bug causes this test to fail when inserting a bigint
if (PHP_INT_SIZE == 4)
{
if (PHP_INT_SIZE == 4) {
echo "Done.\n";
exit();
}
@ -26,14 +25,13 @@ function checkErrors($errors, ...$codes)
{
$codeFound = false;
foreach($codes as $code)
{
if ($code[0]==$errors[0] and $code[1]==$errors[1])
foreach ($codes as $code) {
if ($code[0]==$errors[0] and $code[1]==$errors[1]) {
$codeFound = true;
}
}
if ($codeFound == false)
{
if ($codeFound == false) {
echo "Error: ";
print_r($errors);
echo "\nExpected: ";
@ -73,14 +71,14 @@ function FormulateSetupQuery($tableName, &$dataTypes, &$columns, &$insertQuery)
$strsize = 64;
$dataTypes = array ("char($strsize)", "varchar($strsize)", "nvarchar($strsize)",
$dataTypes = array("char($strsize)", "varchar($strsize)", "nvarchar($strsize)",
"decimal", "float", "real", "bigint", "int", "bit"
);
$tableName = "akv_comparison_table";
// Test every combination of the keywords above.
// Leave out good credentials to ensure that caching does not influence the
// Leave out good credentials to ensure that caching does not influence the
// results. The cache timeout can only be changed with SQLSetConnectAttr, so
// we can't run a PHP test without caching, and if we started with good
// credentials then subsequent calls with bad credentials can work, which
@ -92,25 +90,28 @@ for ($i=0; $i < sizeof($columnEncryption); ++$i) {
for ($m=0; $m < sizeof($keyStoreSecret); ++$m) {
$connectionOptions = "sqlsrv:Server=$server;Database=$databaseName";
if (!empty($columnEncryption[$i]))
if (!empty($columnEncryption[$i])) {
$connectionOptions .= ";ColumnEncryption=".$columnEncryption[$i];
if (!empty($keyStoreAuthentication[$j]))
}
if (!empty($keyStoreAuthentication[$j])) {
$connectionOptions .= ";KeyStoreAuthentication=".$keyStoreAuthentication[$j];
if (!empty($keyStorePrincipalId[$k]))
$connectionOptions .= ";KeyStorePrincipalId=".$keyStorePrincipalId[$k];
if (!empty($keyStoreSecret[$m]))
}
if (!empty($keyStorePrincipalId[$k])) {
$connectionOptions .= ";KeyStorePrincipalId=".$keyStorePrincipalId[$k];
}
if (!empty($keyStoreSecret[$m])) {
$connectionOptions .= ";KeyStoreSecret=".$keyStoreSecret[$m];
}
// Valid credentials getting skipped
if (($i==0 and $j==0 and $k==0 and $m==0) or
if (($i==0 and $j==0 and $k==0 and $m==0) or
($i==0 and $j==1 and $k==1 and $m==1)) {
continue;
}
$connectionOptions .= ";";
try
{
try {
// Connect to the AE-enabled database
$conn = new PDO($connectionOptions, $uid, $pwd);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
@ -146,40 +147,42 @@ for ($i=0; $i < sizeof($columnEncryption); ++$i) {
} else {
// The INSERT query succeeded with bad credentials, which
// should only happen when encryption is not enabled.
if (isColEncrypted())
fatalError( "Successful insertion with bad credentials\n");
if (isColEncrypted()) {
fatalError("Successful insertion with bad credentials\n");
}
}
// Free the statement and close the connection
$stmt = null;
$conn = null;
}
catch(Exception $e)
{
} catch (Exception $e) {
$errors = $e->errorInfo;
if (!isColEncrypted())
{
checkErrors($errors, array('CE258', '0'),
array('CE275', '0'),
array('IMSSP', '-85'),
array('IMSSP', '-86'),
array('IMSSP', '-87'),
array('IMSSP', '-88'),
array('08001', '0'),
array('08001', '-1')); // SSL error occurs in Ubuntu
}
else
{
checkErrors($errors, array('CE258', '0'),
array('CE275', '0'),
array('IMSSP', '-85'),
array('IMSSP', '-86'),
array('IMSSP', '-87'),
array('IMSSP', '-88'),
array('08001', '0'),
array('08001', '-1'), // SSL error occurs in Ubuntu
array('22018', '206'));
if (!isColEncrypted()) {
checkErrors(
$errors,
array('CE258', '0'),
array('CE275', '0'),
array('IMSSP', '-85'),
array('IMSSP', '-86'),
array('IMSSP', '-87'),
array('IMSSP', '-88'),
array('08001', '0'),
array('08001', '-1') // SSL error occurs in Ubuntu
);
} else {
checkErrors(
$errors,
array('CE258', '0'),
array('CE275', '0'),
array('IMSSP', '-85'),
array('IMSSP', '-86'),
array('IMSSP', '-87'),
array('IMSSP', '-88'),
array('08001', '0'),
array('08001', '-1'), // SSL error occurs in Ubuntu
array('22018', '206')
);
}
}
}

Просмотреть файл

@ -1,5 +1,5 @@
--TEST--
Test connection keywords and credentials for Azure Key Vault for Always Encrypted.
Test credentials for Azure Key Vault for Always Encrypted.
--SKIPIF--
<?php require('skipif.inc'); ?>
--FILE--
@ -7,8 +7,7 @@ Test connection keywords and credentials for Azure Key Vault for Always Encrypte
// TODO: Fix the test on Ubuntu - right now it produces a SSL error on Ubuntu
// The following skips Ubuntu to prevent a test failure
$is_ubuntu = php_uname('v');
if (strpos($is_ubuntu, 'buntu') !== false)
{
if (strpos($is_ubuntu, 'buntu') !== false) {
echo "Skipping test on Ubuntu\n";
exit();
}
@ -45,7 +44,7 @@ function FormulateSetupQuery($tableName, &$dataTypes, &$columns, &$insertQuery)
$strsize = 64;
$dataTypes = array ("char($strsize)", "varchar($strsize)", "nvarchar($strsize)",
$dataTypes = array("char($strsize)", "varchar($strsize)", "nvarchar($strsize)",
"decimal", "float", "real", "bigint", "int", "bit"
);
@ -55,7 +54,7 @@ $connectionOptions = "sqlsrv:Server=$server;Database=$databaseName";
$connectionOptions .= ";ColumnEncryption=enabled";
$connectionOptions .= ";KeyStoreAuthentication=KeyVaultPassword";
$connectionOptions .= ";KeyStorePrincipalId=".$AKVPrincipalName;
$connectionOptions .= ";KeyStorePrincipalId=".$AKVPrincipalName;
$connectionOptions .= ";KeyStoreSecret=".$AKVPassword;
$connectionOptions .= ";";
@ -122,7 +121,7 @@ try {
// Free the statement and close the connection
$stmt = null;
$conn = null;
} catch(Exception $e) {
} catch (Exception $e) {
echo "Unexpected error.\n";
print_r($e->errorInfo);
}
@ -196,11 +195,11 @@ try {
// Free the statement and close the connection
$stmt = null;
$conn = null;
} catch(Exception $e) {
} catch (Exception $e) {
echo "Unexpected error.\n";
print_r($e->errorInfo);
}
?>
--EXPECTREGEX--
(Successful insertion and retrieval with username\/password\.\nSuccessful insertion and retrieval with client ID\/secret\.|Skipping test on Ubuntu)
(Successful insertion and retrieval with username\/password\.\nSuccessful insertion and retrieval with client ID\/secret\.|Skipping test on Ubuntu)

Просмотреть файл

@ -1,5 +1,5 @@
--TEST--
Test connection keywords and credentials for Azure Key Vault for Always Encrypted.
Test connection keywords for Azure Key Vault for Always Encrypted.
--SKIPIF--
<?php require('skipif.inc'); ?>
--FILE--
@ -16,17 +16,16 @@ $keyStoreSecret = [$AKVPassword, $AKVSecret, 'notasecret', ''];
$is_win = (strtoupper(substr(php_uname('s'), 0, 3)) === 'WIN');
function checkErrors($errors, ...$codes)
{
{
$codeFound = false;
foreach($codes as $code)
{
if ($code[0]==$errors[0][0] and $code[1]==$errors[0][1])
foreach ($codes as $code) {
if ($code[0]==$errors[0][0] and $code[1]==$errors[0][1]) {
$codeFound = true;
}
}
if ($codeFound == false)
{
if ($codeFound == false) {
echo "Error: ";
print_r($errors);
echo "\nExpected: ";
@ -64,14 +63,14 @@ function FormulateSetupQuery($tableName, &$dataTypes, &$columns, &$insertQuery)
$strsize = 64;
$dataTypes = array ("char($strsize)", "varchar($strsize)", "nvarchar($strsize)",
$dataTypes = array("char($strsize)", "varchar($strsize)", "nvarchar($strsize)",
"decimal", "float", "real", "bigint", "int", "bit"
);
$tableName = "akv_comparison_table";
// Test every combination of the keywords above.
// Leave out good credentials to ensure that caching does not influence the
// Leave out good credentials to ensure that caching does not influence the
// results. The cache timeout can only be changed with SQLSetConnectAttr, so
// we can't run a PHP test without caching, and if we started with good
// credentials then subsequent calls with bad credentials can work, which
@ -81,23 +80,27 @@ for ($i=0; $i < sizeof($columnEncryption); ++$i) {
for ($j=0; $j < sizeof($keyStoreAuthentication); ++$j) {
for ($k=0; $k < sizeof($keyStorePrincipalId); ++$k) {
for ($m=0; $m < sizeof($keyStoreSecret); ++$m) {
$connectionOptions = array("CharacterSet"=>"UTF-8",
"database"=>$databaseName,
"uid"=>$uid,
$connectionOptions = array("CharacterSet"=>"UTF-8",
"database"=>$databaseName,
"uid"=>$uid,
"pwd"=>$pwd,
"ConnectionPooling"=>0);
if (!empty($columnEncryption[$i]))
if (!empty($columnEncryption[$i])) {
$connectionOptions['ColumnEncryption'] = $columnEncryption[$i];
if (!empty($keyStoreAuthentication[$j]))
}
if (!empty($keyStoreAuthentication[$j])) {
$connectionOptions['KeyStoreAuthentication'] = $keyStoreAuthentication[$j];
if (!empty($keyStorePrincipalId[$k]))
$connectionOptions['KeyStorePrincipalId'] = $keyStorePrincipalId[$k];
if (!empty($keyStoreSecret[$m]))
}
if (!empty($keyStorePrincipalId[$k])) {
$connectionOptions['KeyStorePrincipalId'] = $keyStorePrincipalId[$k];
}
if (!empty($keyStoreSecret[$m])) {
$connectionOptions['KeyStoreSecret'] = $keyStoreSecret[$m];
}
// Valid credentials getting skipped
if (($i==0 and $j==0 and $k==0 and $m==0) or
if (($i==0 and $j==0 and $k==0 and $m==0) or
($i==0 and $j==1 and $k==1 and $m==1)) {
continue;
}
@ -105,19 +108,19 @@ for ($i=0; $i < sizeof($columnEncryption); ++$i) {
// Connect to the AE-enabled database
// Failure is expected when the keyword combination is wrong
$conn = sqlsrv_connect($server, $connectionOptions);
if (!$conn)
{
if (!$conn) {
$errors = sqlsrv_errors();
checkErrors($errors, array('08001','0'),
array('08001','-1'), // SSL error occurs in Ubuntu
array('IMSSP','-110'),
array('IMSSP','-111'),
array('IMSSP','-112'),
array('IMSSP','-113'));
}
else
{
checkErrors(
$errors,
array('08001','0'),
array('08001','-1'), // SSL error occurs in Ubuntu
array('IMSSP','-110'),
array('IMSSP','-111'),
array('IMSSP','-112'),
array('IMSSP','-113')
);
} else {
$columns = array();
$insertQuery = "";
@ -149,26 +152,28 @@ for ($i=0; $i < sizeof($columnEncryption); ++$i) {
if (sqlsrv_execute($stmt) == false) {
$errors = sqlsrv_errors();
if (!AE\isColEncrypted())
{
checkErrors($errors, array('CE258', '0'),
array('CE275', '0'));
}
else
{
checkErrors($errors, array('CE258', '0'),
array('CE275', '0'),
array('22018', '206'));
if (!AE\isColEncrypted()) {
checkErrors(
$errors,
array('CE258', '0'),
array('CE275', '0')
);
} else {
checkErrors(
$errors,
array('CE258', '0'),
array('CE275', '0'),
array('22018', '206')
);
}
sqlsrv_free_stmt($stmt);
}
else
{
} else {
// The INSERT query succeeded with bad credentials, which
// should only happen when encryption is not enabled.
if (AE\isColEncrypted())
fatalError( "Successful insertion with bad credentials\n");
if (AE\isColEncrypted()) {
fatalError("Successful insertion with bad credentials\n");
}
}
// Free the statement and close the connection

Просмотреть файл

@ -1,5 +1,5 @@
--TEST--
Test connection keywords and credentials for Azure Key Vault for Always Encrypted.
Test credentials for Azure Key Vault for Always Encrypted.
--SKIPIF--
<?php require('skipif.inc'); ?>
--FILE--
@ -200,4 +200,4 @@ if (!$conn) {
?>
--EXPECTREGEX--
(Successful insertion and retrieval with username\/password\.\nSuccessful insertion and retrieval with client ID\/secret\.|Skipping test on Ubuntu)
(Successful insertion and retrieval with username\/password\.\nSuccessful insertion and retrieval with client ID\/secret\.|Skipping test on Ubuntu)