You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This setup used Windows Server 2016 to generate the certificate.
20
+
Nevertheless it seems there is an issue in Java to read the certificate generated by this operating system version (at least in the PKCS#12 format (.pfx file).
21
+
I used the Oracle JDK 1.8.0_181 and the JDBC driver was unable to read properly the certificate in the JavaKeyStore. This is documented in following bug reports :
These bugs are resolved in the JDK 11 which is not yet publicly available (early access build <a href="http://jdk.java.net/11/">JDK 11</a>. So until general availability you should generate the certificate with:
27
+
<ul>
28
+
<li>A Windows Server 2012 R2 : nevertheless the New-SelfSignedCertificate cmdlet doesn't present all options (especially the -FriendlyName) so it is not suitable.</li>
29
+
<li>A real PKI infrastructure (Windows Server 2012 R2 or below), to create a certificate request with appropriate settings (especially the FriendlyName).</li>
30
+
<li>KeyTool.exe available in the Java JDK. This is finally this option that worked for both the .NET Driver and the JDBC Driver.</li>
31
+
</td>
32
+
</tr>
33
+
</tbody>
34
+
</table>
35
+
36
+
37
+
## KeyTool
38
+
39
+
Using keytool.exe (included with JDK) to generate the certificate :
Output with answers to generate the certificate subject :
46
+
```txt
47
+
What is your first and last name?
48
+
[Unknown]: CLINIC_CMK_GENERIC
49
+
What is the name of your organizational unit?
50
+
[Unknown]: CLINIC
51
+
What is the name of your organization?
52
+
[Unknown]: CLINIC
53
+
What is the name of your City or Locality?
54
+
[Unknown]: BOSTON
55
+
What is the name of your State or Province?
56
+
[Unknown]: IL
57
+
What is the two-letter country code for this unit?
58
+
[Unknown]: US
59
+
Is CN=CLINIC_CMK_GENERIC, OU=CLINIC, O=CLINIC, L=BOSTON, ST=IL, C=US correct?
60
+
[no]: yes
61
+
```
62
+
63
+
Import the certificate in the Windows Certificate store for both the .NET Client and Security administrator system. Provide the certificate to the JDBC client as file. Do not provide the certificate to DBA administrator.
64
+
All this roles are described in details on [next steps](2.CreateGenericCMK-CEK.md) :
With the issue described above, Java clients using a certificate generated with a Windows Server 2016 operating system will not be able to decrypt properly encrypted columns. So this script is just for information purpose until JDK 11 availability.
Copy file name to clipboardExpand all lines: 2.CreateGenericCMK-CEK.md
+37-6
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,17 @@
2
2
3
3
This scenario use the Key provising with role separation provided by [Microsoft](https://docs.microsoft.com/en-us/sql/relational-databases/security/encryption/configure-always-encrypted-keys-using-powershell?view=sql-server-2017#KeyProvisionWithRoles).
4
4
5
-
### <spanid="setup">Setup environment for Generic Provider usage</span>
5
+
There is 2 distinguished roles :
6
+
- The security administrator, which has access to the certificate.
7
+
- The database (DBA) administrator, which has no access to the certificate.
8
+
9
+
While this scenario use a complete role separation, for the sake of simplicity everything was performed on the same computer. I just removed the certificate from the Windows Certificate store for the DBA administrator steps.
10
+
11
+
So I only setup environment once for both.
12
+
13
+
## <spanid="setup">Setup environment for Generic Provider usage</span>
14
+
15
+
This step must de done only once per computer. This download the PowerShell SqlServer module and overwrite the Microsoft dll with the [patched one](bin\SQLServerAlwaysEncrypted.dll) (making a backup of the originating dll).
Register the generic provider. Be careful with the order of the commands.
91
+
Once the SqlServer PowerShell module is imported, not all assemblies are loaded until you use one cmdlet of the module. At this step, no cmdlet from the SqlServer is used yet. The first command "fake" a call to any SqlServer cmdlet to load all the assemblies used by the module. This initialize the internal dictionnay of custom providers.
79
92
93
+
```PowerShell
80
94
<#internally Always Encrypted Microsoft cmdlets do not load directly the [Microsoft.SqlServer.Management.AlwaysEncrypted.Management] assembly.
All cmdlets related to CMK/CEK follow this call chain.
86
-
All cmdlets related to columns encryption use directly the [System.Data.SqlClient] assembly.
99
+
All cmdlets related to CMK / CEK use this call chain and use the [Microsoft.SqlServer.Management.AlwaysEncrypted.Management]::CustomProviders dictionnary.
100
+
All cmdlets related to columns encryption use directly the [System.Data.SqlClient] assembly and its internal dictionnary of custom providers.
# Create a SqlColumnMasterKeySettings object (the CMK metadata) with information about the generic provider. KeyPath must not be empty. Here i use "NONE", but this may be the certificate thumbprint or whatever you want. This is not important because the generic provider is already configured with the real keypath to the wrapped provider.
@@ -158,6 +180,9 @@ The DBA administrator has no access to the certificate. The DBA administrator mu
158
180
159
181
160
182
```PowerShell
183
+
#Import the module
184
+
Import-Module "SqlServer"
185
+
161
186
# Obtain the location of the column master key and the encrypted value of the column encryption key from your Security Administrator, via a CSV file on a share drive.
The [Java/SQLServerAlwaysEncrypted](JAVA/SQLServerAlwaysEncrypted) project contains both :
4
+
- the Generic Provider (wrapping the JAVA_KEY_STORE provider).
5
+
- a sample to query the database.
6
+
7
+
The details of the sample are :
8
+
- get a connectionString (from arguments)
9
+
- Create the wrapped provider (JAVA_KEY_STORE) with right settings.
10
+
- Create the generic provider (GENERIC) with the wrapped provider, providing the right path for the wrapped provider.
11
+
- Create a SQL command with parameters
12
+
- Execute Query
13
+
- Check the request is successfull and data unencrypted
14
+
15
+
16
+
The JAVA_KEY_STORE needs 2 parameters in its constructor (static String in code) :
17
+
- KeyStorePath : the path to the certificate on the file system (.pfx file)
18
+
- KeyStorePassword : the password to open the key store (see [Create Key](1-CreateKey.md))
19
+
20
+
The CMK does not provide any valid value for the key path. The JAVA_KEY_STORE require this path being the FriendlyName property of the certificate.
21
+
22
+
Create an instance of the GENERIC_KEY_STORE, providing both the wrapped JAVA_KEY_STORE instance and the friendlyname of the certificate as path ("clinic_cmk_generic" in the [sample](1-CreateKey.md)).
23
+
24
+
To keep authentication simple with this sample, I created a new account (admin P@ssw0rd) in SSMS.
25
+
26
+
Provide the connectionstring as arguments (if you use the sample database CLINIC) :
Copy file name to clipboardExpand all lines: Issue1.md
+6-3
Original file line number
Diff line number
Diff line change
@@ -1,4 +1,5 @@
1
-
# PS Module unable to retrieve a registered custom provider
1
+
# SqlServer PowerShell Module unable to find a registered custom provider
2
+
2
3
3
4
## Microsoft Code
4
5
Initial code from the Microsoft.SqlServer.Management.AlwaysEncrypted.Management.dll:
@@ -32,11 +33,13 @@ public static class AlwaysEncryptedManagement {
32
33
33
34
The main issue in this code is the default statement. Only an error is returned whenever you attempt to access a custom provider. Normally the code should behave as in the "AZURE_KEY_VAULT" statement.
34
35
35
-
With the original code, it is impossible to achieve Always Encrypted configuration with PowerShell and a custom/generic provider. It may be possible with a full C# or Java, but all the documentation use PowerShell.
36
+
With the original code, it is impossible to achieve Always Encrypted configuration with PowerShell and a custom/generic provider. It may probably be possible with a full C# or Java, but all the documentation used PowerShell.
37
+
38
+
In an effort to use PowerShell for this scenario, a solution was necessary.
36
39
37
40
## Patched DLL
38
41
39
-
The [provided patched DLL](bin/Microsoft.SqlServer.Management.AlwaysEncrypted.Management.dll) replace the Microsoft original code with the following simple code. I was not really able to properly insert IL to replace only the default statement from the original code. But it doesn't have any importance, being able to retrieve a custom/generic provider is sufficient.
42
+
The [provided patched DLL](bin/Microsoft.SqlServer.Management.AlwaysEncrypted.Management.dll) replace the Microsoft original code with the following simple code. I was not really able to properly insert IL code to replace only the default statement from the original code. But it doesn't have any importance, being able to retrieve a custom/generic provider is sufficient.
Copy file name to clipboardExpand all lines: Issue2.md
+1-1
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
3
3
## Information about the issue
4
4
5
-
One of the issue encountered during development of this generic provider was the moment where you want to encrypt columns. The cmdlet used to encrypt the columns does use the [System.Data.SqlClient.SqlConnection] object to get access to registered custom providers.
5
+
One of the issue encountered during development of this generic provider was the moment where you want to encrypt columns. The cmdlet used to encrypt the columns use the [System.Data.SqlClient.SqlConnection] object to get access to registered custom providers.
6
6
7
7
By following the <ahref="#callstack">callstack</a> from the load of the PowerShell module, it is clear that both the PowerShell module and the code from [System.Data.SqlClient] present some issues:
8
8
- The SqlServer PowerShell module loads the "AZURE_KEY_VAULT" as a custom provider and by doing so prevent any other registration of a custom provider.
0 commit comments