Reputation: 4685
I am trying to create an UNSAFE assembly in SQL Server without having to alter any global database or server permissions such as EXEC sp_configure 'clr strict security', 0
or ALTER DATABASE MyDatabase SET TRUSTWORTHY ON
(because I'm not allowed to do either of those things on our production server). Therefore I am trying to create an asymmetric key that has a corresponding login with UNSAFE ASSEMBLY
permission as instructed by SSMS.
I run the command
use MyDatabase
CREATE ASYMMETRIC KEY MyUtilsKey
FROM EXECUTABLE FILE = 'C:\Users\Me\MyCode\MyUtils.dll';
and I receive the error
--The certificate, asymmetric key, or private key file is not valid or does not exist; or you do not have permissions for it.
I am the owner of MyDatabase
and I have verfied that the path to the file is correct. I have also verified that MyUtils.dll is signed and has a valid key pair from the command-line as follows:
sn -v MyUtils.dll # Assembly 'MyUtils.dll' is valid
sn -p MyUtils.snk publicKey.snk # Public key written to publicKey.snk
sn -tp publicKey.snk # Public key (hash algorithm: sha1): [hex key], Public key token is [hex token]
I don't know what else to try.
EDIT: I am using SQL Server 16.0.1105.1.
Upvotes: 1
Views: 1658
Reputation: 48776
First, just to get an obvious question / issue out of the way:
I am trying to create an ... assembly in SQL Server without having to alter any global database or server permissions...
Is SQLCLR enabled on this server / instance? That is a server permission that is disabled by default. If it's not already enabled, and you're not allowed to make such changes, then the rest of this answer won't make a difference. If you aren't sure, execute the following:
EXEC sys.sp_configure 'CLR enabled';
If the run_value
column (far right) shows 1
, then you are good. Else, you need to start talking to some folks at your organization before continuing.
Assuming that SQLCLR is enabled in production, then you are off to a good start by having the assembly signed with an asymmetric key (i.e. strongly named).
The ability to load a non-SAFE
assembly, or any assembly starting in SQL Server 2017 (you haven't specified which version you're using) is controlled by the EXTERNAL ACCESS ASSEMBLY
and UNSAFE ASSEMBLY
server-level permissions (i.e. permissions assigned to a Login, not to a DB-level User).
The asymmetric key used to sign your assembly needs to be created in the [master]
database, not in the database where you are attempting to load the assembly (unless that DB is [master]
, of course), as it will be used to create a Login. (Side Note: hopefully you have permission to create both an Asymmetric Key, and a Login from that key, in the [master]
database, else again, this information won't help).
My preference has always been to load assemblies and keys from their binary string representation (i.e. hex "bits" as referred to by the SQL Server documentation). This avoids any potential file system permission issues as everything can be in a single, self-contained SQL script. Unfortunately, because Microsoft refuses to add the FROM BINARY =
option to CREATE ASYMMETRIC KEY
(I've been begging them for many years now), we have to find a different way.
Prior to SQL Server 2017, which introduced the horrible, and most likely entirely unnecessary server option CLR strict security
, we could create an empty SAFE
assembly, signed by the same key, load that into [master]
, and extract the asymmetric key from it. But now even SAFE
assemblies require security set up prior to loading.
This leads to a convoluted, yet effective, approach using Certificates, since they can be created from a binary string / hex bytes. But, the assembly isn't signed by a certificate, it's signed by a strong name key (i.e. asymmetric key). That leaves us with the following approach:
[SqlProcedure]
method that doesn't do anything, or just declares a variable.FROM BINARY = 0x....
) in [master]
from the certificate used to sign the empty assembly. {this will be temporary}[master]
. {this will be temporary}UNSAFE ASSEMBLY
permission.[master] (using
FROM 0x....`). {this will be temporary}[master]
from the new Assembly.UNSAFE ASSEMBLY
permission.Now you can load any Assembly signed with that same Asymmetric Key / Strong Name Key (.snk) into any database.
For a more detailed look at the steps noted above, please see the following post of mine:
SQLCLR vs. SQL Server 2017, Part 2: “CLR strict security” – Solution 1
P.S. If Microsoft were to accept my suggestion of adding the FROM BINARY =
option to CREATE ASYMMETRIC KEY
, just like it works for CREATE CERTIFICATE
, then the steps described here could be reduced to simply:
[master]
from the strong name key (.snk file) used to sign the assembly(ies) (using FROM BINARY = 0x....
).UNSAFE ASSEMBLY
permission.AND, that could be automated by SSDT, if they wanted to. It would make developing and deploying SQLCLR 1000 times easier, which I guess is why they aren't in a hurry to do it. Though it would also make SQL Server more secure because it would drastically reduce the number of people using SET TRUSTWORTHY ON
simply due to needing to deploy an assembly and either not knowing how to do these steps, or not having the time and/or patience for the extra steps. 😿
P.P.S. It is also possible to use Certificates instead of an Asymmetric Key / strong name key (.snk file). Doing so will allow for a much simpler process than what was initially described above (and get closer to the ideal process if only Microsoft would add the FROM BINARY =
option to CREATE ASYMMETRIC KEY
). This is due to being able to create Certificates in SQL Server using FROM BINARY = 0x....
(like we saw above). If the Assembly (i.e. .dll file) is signed with a certificate, then there's no need for the empty Assembly used only to get the Asymmetric Key loaded into [master]
, and all of the steps associated with it.
You will still need to create a Certificate, and because "signing" within Visual Studio / SSDT really means "strong naming" (i.e. using a .snk file / Asymmetric Key), you will need to do a one-time (per Project / Assembly) manual update of the .sqlproj file to allow for using the Certificate (assuming you want to use Visual Studio / SSDT for publishing to SQL Server).
For a more detailed look at this option / method, please see the following post of mine:
SQLCLR vs. SQL Server 2017, Part 3: “CLR strict security” – Solution 2
Upvotes: 3
Reputation: 4685
siggemannen was essentially right in his comment. When creating an asymmetric key from a DLL, the DLL must not reside in a subdirectory of C:\Users
, even if you are running a local instance of SQL Server.
So the correct sequence of steps (if you don't mind creating a key from an external DLL file) is as follows (with a nod of gratitude to Solomon Rutzky for his comprehensive answer and many other blog posts on the subject):
C:\Temp
).EXEC sp_configure 'clr enabled', 1;
.master
database with USE master
.CREATE ASYMMETRIC KEY MyUtilsKey FROM EXECUTABLE FILE = 'C:\Temp\MyUtils.dll';
That gets you as far as creating the asymmetric key (provided you have the necessary privileges to run these commands). To go on and create the assembly from it requires these extra steps:
master
) Create a new SQL Server principal from the asymmetric key with CREATE LOGIN MyUtilsKeyLogin FROM ASYMMETRIC KEY MyUtilsKey
.UNSAFE ASSEMBLY
with GRANT UNSAFE ASSEMBLY TO MyUtilsKeyLogin;
.USE MyDatabase
.CREATE ASSEMBLY MyUtils FROM 'C:\Temp\MyUtils.dll' WITH PERMISSION_SET = [UN]SAFE;
Two further points to note:
CREATE ASSEMBLY MyUtils FROM 'C:\Users\Me\MyCode\MyUtils.dll' ...
actually works! SQL Server can actually create assemblies from DLLs in subdirectories of C:\Users
. (I have proven this many times in testing.) It just can't create asymmetric keys from DLLs in those directories. I have no idea why, and it threw me off the scent for days.GRANT UNSAFE ASSEMBLY TO MyUtilsKeyLogin;
is still required even if all your assemblies are SAFE
! Microsoft changed the default behaviour in SQL Server 2017 and Solomon Rutzky has written extensively on this topic (e.g., https://sqlquantumleap.com/2017/08/07/sqlclr-vs-sql-server-2017-part-1-clr-strict-security/). I can highly recommend his comprehensive tutorial on the SQL CLR at https://www.sqlservercentral.com/steps/stairway-to-sqlclr-level-1-what-is-sqlclr.Upvotes: 1