diff --git a/source/pdo_sqlsrv/pdo_dbh.cpp b/source/pdo_sqlsrv/pdo_dbh.cpp index da2bc727..6a35dd03 100644 --- a/source/pdo_sqlsrv/pdo_dbh.cpp +++ b/source/pdo_sqlsrv/pdo_dbh.cpp @@ -42,6 +42,7 @@ const char ApplicationIntent[] = "ApplicationIntent"; const char AttachDBFileName[] = "AttachDbFileName"; const char ConnectionPooling[] = "ConnectionPooling"; const char Authentication[] = "Authentication"; +const char ColumnEncryption[] = "ColumnEncryption"; #ifdef _WIN32 const char ConnectRetryCount[] = "ConnectRetryCount"; const char ConnectRetryInterval[] = "ConnectRetryInterval"; @@ -220,6 +221,15 @@ const connection_option PDO_CONN_OPTS[] = { CONN_ATTR_BOOL, conn_null_func::func }, + { + PDOConnOptionNames::ColumnEncryption, + sizeof(PDOConnOptionNames::ColumnEncryption), + SQLSRV_CONN_OPTION_COLUMNENCRYPTION, + ODBCConnOptions::ColumnEncryption, + sizeof(ODBCConnOptions::ColumnEncryption), + CONN_ATTR_STRING, + column_encryption_set_func::func + }, #ifdef _WIN32 { PDOConnOptionNames::ConnectRetryCount, diff --git a/source/shared/core_sqlsrv.h b/source/shared/core_sqlsrv.h index 6f904f72..491a96fc 100644 --- a/source/shared/core_sqlsrv.h +++ b/source/shared/core_sqlsrv.h @@ -1044,6 +1044,16 @@ enum DRIVER_VERSION : size_t { struct sqlsrv_stmt; struct stmt_option; +// This holds the various details of column encryption. +struct col_encryption_option { + bool enabled; // column encryption enabled, false by default + size_t key_size; // the length of ksp_encrypt_key without the NULL terminator + + col_encryption_option() : enabled(false), key_size(0) + { + } +}; + // *** connection resource structure *** // this is the resource structure returned when a connection is made. struct sqlsrv_conn : public sqlsrv_context { @@ -1051,7 +1061,9 @@ struct sqlsrv_conn : public sqlsrv_context { // instance variables SERVER_VERSION server_version; // version of the server that we're connected to - DRIVER_VERSION driver_version; + DRIVER_VERSION driver_version; + + col_encryption_option ce_option; // holds the details of what are required to enable column encryption // initialize with default values sqlsrv_conn( _In_ SQLHANDLE h, _In_ error_callback e, _In_opt_ void* drv, _In_ SQLSRV_ENCODING encoding TSRMLS_DC ) : @@ -1085,6 +1097,7 @@ const char APP[] = "APP"; const char ApplicationIntent[] = "ApplicationIntent"; const char AttachDBFileName[] = "AttachDbFileName"; const char Authentication[] = "Authentication"; +const char ColumnEncryption[] = "ColumnEncryption"; const char CharacterSet[] = "CharacterSet"; const char ConnectionPooling[] = "ConnectionPooling"; #ifdef _WIN32 @@ -1131,6 +1144,7 @@ enum SQLSRV_CONN_OPTIONS { SQLSRV_CONN_OPTION_APPLICATION_INTENT, SQLSRV_CONN_OPTION_MULTI_SUBNET_FAILOVER, SQLSRV_CONN_OPTION_AUTHENTICATION, + SQLSRV_CONN_OPTION_COLUMNENCRYPTION, SQLSRV_CONN_OPTION_TRANSPARANT_NETWORK_IP_RESOLUTION, #ifdef _WIN32 SQLSRV_CONN_OPTION_CONN_RETRY_COUNT, @@ -2364,4 +2378,24 @@ struct str_conn_attr_func { } }; +struct column_encryption_set_func { + + static void func(connection_option const* option, zval* value, sqlsrv_conn* conn, std::string& conn_str TSRMLS_DC) + { + convert_to_string(value); + const char* value_str = Z_STRVAL_P(value); + + // Column Encryption is disabled by default unless it is explicitly 'Enabled' + conn->ce_option.enabled = false; + if (!stricmp(value_str, "enabled")) { + conn->ce_option.enabled = true; + } + + conn_str += option->odbc_name; + conn_str += "="; + conn_str += value_str; + conn_str += ";"; + } +}; + #endif // CORE_SQLSRV_H diff --git a/source/sqlsrv/conn.cpp b/source/sqlsrv/conn.cpp index 8da98f30..f4341fbe 100644 --- a/source/sqlsrv/conn.cpp +++ b/source/sqlsrv/conn.cpp @@ -188,6 +188,7 @@ const char AttachDBFileName[] = "AttachDbFileName"; const char CharacterSet[] = "CharacterSet"; const char Authentication[] = "Authentication"; const char ConnectionPooling[] = "ConnectionPooling"; +const char ColumnEncryption[] = "ColumnEncryption"; #ifdef _WIN32 const char ConnectRetryCount[] = "ConnectRetryCount"; const char ConnectRetryInterval[] = "ConnectRetryInterval"; @@ -302,6 +303,15 @@ const connection_option SS_CONN_OPTS[] = { CONN_ATTR_BOOL, conn_null_func::func }, + { + SSConnOptionNames::ColumnEncryption, + sizeof(SSConnOptionNames::ColumnEncryption), + SQLSRV_CONN_OPTION_COLUMNENCRYPTION, + ODBCConnOptions::ColumnEncryption, + sizeof(ODBCConnOptions::ColumnEncryption), + CONN_ATTR_STRING, + column_encryption_set_func::func + }, #ifdef _WIN32 { SSConnOptionNames::ConnectRetryCount, diff --git a/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt b/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt new file mode 100644 index 00000000..1416b211 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt @@ -0,0 +1,69 @@ +--TEST-- +Test new connection keyword ColumnEncryption +--SKIPIF-- + +--FILE-- +getMessage() ); + echo "\n"; + } + $conn = null; + //////////////////////////////////////// + $connectionInfo = "Database = $databaseName; ColumnEncryption = false;"; + try + { + $conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd ); + } + catch( PDOException $e ) + { + echo "Failed to connect.\n"; + print_r( $e->getMessage() ); + echo "\n"; + } + //////////////////////////////////////// + $connectionInfo = "Database = $databaseName; ColumnEncryption = 1;"; + try + { + $conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd ); + } + catch( PDOException $e ) + { + echo "Failed to connect.\n"; + print_r( $e->getMessage() ); + echo "\n"; + } + + //////////////////////////////////////// + $connectionInfo = "Database = $databaseName; ColumnEncryption = Disabled;"; + try + { + $conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd ); + echo "Connected successfully with ColumnEncryption disabled.\n"; + } + catch( PDOException $e ) + { + echo "Failed to connect with ColumnEncryption disabled.\n"; + print_r( $e->getMessage() ); + echo "\n"; + } + $conn = null; + echo "Done\n"; +?> +--EXPECTREGEX-- +Connected successfully with ColumnEncryption enabled. +Failed to connect. +SQLSTATE\[08001\]: .*\[Microsoft\]\[ODBC Driver 13 for SQL Server\]Invalid value specified for connection string attribute 'ColumnEncryption' +Failed to connect. +SQLSTATE\[08001\]: .*\[Microsoft\]\[ODBC Driver 13 for SQL Server\]Invalid value specified for connection string attribute 'ColumnEncryption' +Connected successfully with ColumnEncryption disabled. +Done \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_connect_encrypted.phpt b/test/functional/sqlsrv/sqlsrv_connect_encrypted.phpt new file mode 100644 index 00000000..4d6c9bac --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_connect_encrypted.phpt @@ -0,0 +1,87 @@ +--TEST-- +Test new connection keyword ColumnEncryption +--SKIPIF-- + +--FILE-- +$databaseName, "UID"=>$uid, "PWD"=>$pwd, + "ColumnEncryption"=>'Enabled'); + $conn = sqlsrv_connect( $server, $connectionInfo ); + if( $conn === false ) + { + echo "Failed to connect.\n"; + print_r( sqlsrv_errors() ); + } + else + { + echo "Connected successfully with ColumnEncryption enabled.\n"; + sqlsrv_close( $conn ); + } + + //////////////////////////////////////// + $connectionInfo['ColumnEncryption']='false'; + $conn = sqlsrv_connect( $server, $connectionInfo ); + if( $conn === false ) + { + echo "Failed to connect.\n"; + print_r( sqlsrv_errors() ); + } + //////////////////////////////////////// + $connectionInfo['ColumnEncryption']=true; + $conn = sqlsrv_connect( $server, $connectionInfo ); + if( $conn === false ) + { + echo "Failed to connect.\n"; + print_r( sqlsrv_errors() ); + } + //////////////////////////////////////// + $connectionInfo['ColumnEncryption']='Disabled'; + $conn = sqlsrv_connect( $server, $connectionInfo ); + if( $conn === false ) + { + echo "Failed to connect.\n"; + print_r( sqlsrv_errors() ); + } + else + { + echo "Connected successfully with ColumnEncryption disabled.\n"; + sqlsrv_close( $conn ); + } + + echo "Done\n"; +?> +--EXPECTREGEX-- +Connected successfully with ColumnEncryption enabled. +Failed to connect. +Array +\( + \[0\] => Array + \( + \[0\] => 08001 + \[SQLSTATE\] => 08001 + \[1\] => 0 + \[code\] => 0 + \[2\] => .*\[Microsoft\]\[ODBC Driver 13 for SQL Server\]Invalid value specified for connection string attribute 'ColumnEncryption' + \[message\] => .*\[Microsoft\]\[ODBC Driver 13 for SQL Server\]Invalid value specified for connection string attribute 'ColumnEncryption' + \) + +\) +Failed to connect. +Array +\( + \[0\] => Array + \( + \[0\] => IMSSP + \[SQLSTATE\] => IMSSP + \[1\] => -33 + \[code\] => -33 + \[2\] => Invalid value type for option ColumnEncryption was specified. String type was expected. + \[message\] => Invalid value type for option ColumnEncryption was specified. String type was expected. + \) + +\) +Connected successfully with ColumnEncryption disabled. +Done \ No newline at end of file