├── README.md └── azure-code-signing-for-plugin-developers.md /README.md: -------------------------------------------------------------------------------- 1 | # 🐨 KoalaDocs 2 | 3 | A collection of useful articles for audio plugin developers. 4 | 5 | #### Get in touch 6 | 7 | This repository has been brought to you by KoalaDSP. Get in touch with us at letstalk@koaladsp.com. 8 | -------------------------------------------------------------------------------- /azure-code-signing-for-plugin-developers.md: -------------------------------------------------------------------------------- 1 | # Azure Trusted Signing for plugin developers 2 | 3 | 🌠 Latest update: Sep 8, 2025 by [Cecill Etheredge](https://github.com/ijsf). 4 | 5 | This guide covers the steps necessary to set up a modern code signing flow using Azure Trusted Signing on Microsoft Windows, for example as part of a automated build or CI process. It is primarily meant for developers that are working on audio plugins and apps and covers a few specifics on things such as AAX code signing, PACE wrapped binaries, with the hope that it will be useful for some. 6 | 7 | [Azure Trusted Signing](https://azure.microsoft.com/en-us/products/trusted-signing) is a new end-to-end code signing service which is currently available to the general public as part of Microsoft Azure. 8 | 9 | We recommend this service because it is provided by Microsoft itself and as such all tools come directly from Microsoft, removing the need for any third party tools to make code signing work, or for any hardware-backed certificate setups. All in all, our experience with it has been very good. 10 | 11 | ## 1. Current state of affairs 12 | 13 | Since 2022, code signing certificates (EV) for Microsoft Windows are no longer allowed to be derived from "unprotected" private key files. Private keys must be generated securely in a Hardware Security Module (HSM) with FIPS 140-2 or EAL 4+ rating, and thus a HSM is now a necessity for plain old local code signing. 14 | 15 | Normally one would use `signtool.exe` with a local private key file belonging to a public-private certificate keypair issued by one of the allowed authorities, but this no longer works without use of a local HSM such as a Yubikey dongle. This can complicate things because you now need either a local HSM, a dedicated shared HSM or remote HSM. 16 | 17 | Fortunately, there are currently at least two viable alternatives out there that will be covered in this guide. 18 | 19 | 1. Azure Trusted Signing - a new Azure service aimed specifically at code signing, which we can recommend. 20 | 2. Azure Key Vault - an Azure service that provides a remote HSM. 21 | 22 | As the Azure Key Vault is a replacement for HSM use cases, will cover the use of the much easier Azure Trusted Signing in this guide instead. 23 | 24 | ## 2. Azure Trusted Signing 25 | 26 | ⚠ Please note that there are currently at least two ways of using Azure Trusted Signing: 27 | 28 | 1. The **_official_** `signtool.exe` and its [Trusted Signing Dlib extension](https://learn.microsoft.com/en-us/azure/trusted-signing/how-to-signing-integrations) as supported by Microsoft. 29 | 2. The **_unofficial_** [AzureSignTool](https://github.com/vcsjones/AzureSignTool), a separate handy tool not maintained by Microsoft. 30 | 31 | This guide focuses on using the _official Microsoft signtool_ because of the long-term support benefits, though the _unofficial AzureSignTool_ (2) may just as well be a viable option for you. 32 | 33 | The way the official Trusted Signing tool works is by extending the existing Microsoft supplied `signtool.exe` with a dynamic library for Azure support. The connection to Azure is used to create and use an ad hoc certificate which is then used to sign a binary. These certificates are issued by Microsoft. In fact, Microsoft itself acts as a certificate authority with a root certificate chain already preinstalled in modern versions of Microsoft Windows. 34 | 35 | Unlike certificates issued from authorities such as Sectigo, DigiCert and others, the certificates issued by Azure Trusted Signing are only valid for a short time (e.g. several days) so that leaked certificates cannot be abused easily by malicious actors. To be fair, the new requirement for a HSM to store these certificates, instead of a file, also makes this much less likely but still. 36 | 37 | In any case, `signtool.exe` automatically and transparently takes care of issuing a new certificates when necessary. In this sense, it is very common to modern non-profit certificate authorities such as [Let's Encrypt](https://letsencrypt.com). 38 | 39 | ### 2.1. Pricing 40 | 41 | The [pricing plan of Azure Trusted Signing](https://azure.microsoft.com/en-us/pricing/details/trusted-signing/) is based on a reasonable monthly fee with a maximum quota of signatures per month (e.g. 5000 signatures per month) after which a per-signature cost gets activated. There is also a bigger tier if you require much more signatures per month, e.g. if you're running extensive CI systems or such. Typically the smallest tier will probably work for most independent developers. 42 | 43 | ### 2.2. Setting up Azure Trusted Signing on Microsoft Azure 44 | 45 | The following assumes that you have access to the Azure Trusted Signing service in your Microsoft Azure account. 46 | 47 | These steps will involve using the Microsoft Azure web portal to configure things. It will only be necessary to configure these things _once_, and you should be good to go afterwards. 48 | 49 | First of all, you will need to look up your tenant id in the Azure Portal: 50 | 51 | * In the Azure portal, go to or search for [Microsoft Entra ID](https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/Overview). 52 | * Your tenant id should be visible under Basic information. 53 | 54 | 💡 _Note down the tenant id, as we will be using this later in this guide._ 55 | 56 | #### 2.2.1. Creating a Trusted Signing Account 57 | 58 | We will start by creating an _Trusted Signing Account_ on Azure. 59 | 60 | 1. Go to [Trusted Signing Accounts](https://ms.portal.azure.com/#browse/Microsoft.CodeSigning%2Fcodesigningaccounts) 61 | 2. Click "Create". Fill in the details, pick one of the following regions: 62 | * East US (https://eus.codesigning.azure.net) 63 | * West US (https://wus.codesigning.azure.net) 64 | * West Central US (https://wcus.codesigning.azure.net) 65 | * West US 2 (https://wus2.codesigning.azure.net) 66 | * North Europe (https://neu.codesigning.azure.net) 67 | * West Europe (https://weu.codesigning.azure.net) 68 | 69 | 💡 _Note down the region, as we will be using this later in this guide._ 70 | 71 | #### 2.2.2. Granting administrative access 72 | 73 | Now that we have a _Trusted Signing Account_, we need to grant your account administrative access in order to access it: 74 | 75 | * Click on your Trusted Signing Account in [Trusted Signing Accounts](https://ms.portal.azure.com/#browse/Microsoft.CodeSigning%2Fcodesigningaccounts). 76 | * Go to "Access control (IAM)" (left menu). 77 | * Click "Add" and "Add role assignment" (top). 78 | * Search for "Trusted Signing Identity Verifier" (job function roles). Next. 79 | * Type in and select your current user account. 80 | * Keep clicking "Review + assign" until done. 81 | 82 | Your account should now have administrative access to Trusted Signing. 83 | 84 | #### 2.2.3. Create a code signing app 85 | 86 | We will now create a _code signing app_, for which the credentials will be used with `signtool.exe`: 87 | 88 | * In the Azure portal, go to or search for [Microsoft Entra ID](https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/Overview). 89 | * Click "Add" and "App registration" (top). 90 | * Name: codesigning-app (or anything else) 91 | * Who can use this application or access this API?: Accounts in this organizational directory only (Default Directory only - Single tenant) 92 | * Redirect URI: (leave as is) 93 | * Click "Register". 94 | * Click on the app resource you've just created. 95 | * Note down the "Application (client) ID" for later usage with signtool. 96 | * Go to "Certificates & secrets" (left menu). 97 | * Click "Client secrets" (top). 98 | * Click "New client secret". 99 | * Set "Expires" to the highest date possible. 100 | * Click "Add". 101 | * Note down the "Value", this is the secret for later usage with signtool. 102 | 103 | 💡 _Note down the code signing app client ID and client secret, which we will use later in this guide._ 104 | 105 | #### 2.2.4. Granting code signing app permissions 106 | 107 | We will now grant Trusted Signing permissions to our code signing app: 108 | 109 | * Click on your Trusted Signing Account in [Trusted Signing Accounts](https://ms.portal.azure.com/#browse/Microsoft.CodeSigning%2Fcodesigningaccounts). 110 | * Go to "Access control (IAM)" (left menu). 111 | * Click "Add" and "Add role assignment" (top). 112 | * Select "Trusted Signing Certificate Profile Signer". Next. 113 | * Leave "User, Group or Service principal" selected. Click on "+ Select Members". 114 | * Type in and select your app name (e.g. codesigning-app). 115 | * Keep clicking "Review + assign" until done. 116 | 117 | #### 2.2.5. Verify identity 118 | 119 | Now that the Trusted Signing resources have been set up, we need to set up Trusted Signing so it can issue new certificates for code signing. 120 | 121 | _One very important requirement for this is that your personal or company identity has been validated with Microsoft Azure._ 122 | 123 | If you have not _validated_ yet, proceed as follows: 124 | 125 | * Click on your Trusted Signing Account in [Trusted Signing Accounts](https://ms.portal.azure.com/#browse/Microsoft.CodeSigning%2Fcodesigningaccounts). 126 | * Go to "Objects" -> "Identity validation" (left menu). 127 | * Click "New" and "Public Trust" (top). 128 | * Fill in the details. Note that Primary and Secondary E-mail(s) will not be published in any certificate. You may need a DUNS number as well. 129 | 130 | Your mileage may vary, but expect the validation to take at least a day to be confirmed as it is a one-time verification that concerns your Microsoft Azure account. 131 | 132 | #### 2.2.6. Create certificate profile 133 | 134 | We now need to create a _certificate profile_, which we can use for code signing to issue new certificates: 135 | 136 | * Click on your Trusted Signing Account in [Trusted Signing Accounts](https://ms.portal.azure.com/#browse/Microsoft.CodeSigning%2Fcodesigningaccounts). 137 | * Go to "Objects" -> "Certificate profiles" (left menu). 138 | * Click "Create" and "Public Trust" (top). 139 | * Fill in a name and select the "Verified CN and O" appropriately (will appear when the identity validation process is done). 140 | * Click "Create". 141 | 142 | 💡 _Note down the Name of the certificate profile, as we will using this later in this guide._ 143 | 144 | The certificate profile should now be set up correctly, so `signtool.exe` can create new certificates on demand. 145 | 146 | 👍 Our setup on the Microsoft Azure portal side of things should now be complete. 147 | 148 | ## 2.3. Setting up Azure Trusted Signing for code signing 149 | 150 | Now that Trusted Signing has been configured in the Microsoft Azure portal, we can set up the code signing tools on our local machine or automated build machine. 151 | 152 | The following steps assume that you have access to a machine running a recent version of Microsoft Windows, and you are able to execute commands in the command prompt with administrative rights. 153 | 154 | #### 2.3.1. Preparing the Azure CLI 155 | 156 | We will need to install the Azure Command-Line Interface tools in order to make `signtool.exe` work with Azure Trusted Signing. This only needs to be done once. The CLI tools will be installed on your system, and will be accessible from a command prompt afterwards. 157 | 158 | * Install the [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-windows?tabs=azure-cli). 159 | 160 | The CLI should be accessible from a command prompt afterwards. If you have one open, reopen it and run `az` to verify that it has been installed correctly. 161 | 162 | We now need to create a "service principal" locally to enable our code signing tools to work. Use the following commands: 163 | 164 | * Log in with the CLI using your admin/owner account: 165 | ```dos 166 | az login 167 | ``` 168 | This will either open your browser, or give you a link through which you should log in to the Azure portal. 169 | * Execute the following manual commands using the CLI 170 | ```dos 171 | az ad sp create --id cf2ab426-f71a-4b61-bb8a-9e505b85bc2e 172 | az ad app permission grant --id cf2ab426-f71a-4b61-bb8a-9e505b85bc2e --api 00000003-0000-0000-c000-000000000000 --scope User.Read 173 | ``` 174 | 175 | ⚠ If you have issues logging into Azure with `az login`, specifically regarding tenant id's, you may have installed Azure before and used a different account (or tenant). You can always find your tenant ID in the Microsoft Azure Portal under [Microsoft Entra ID](https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/Overview). and pass this in with the `--tenant-id ...` argument if needed. 176 | 177 | Note that these commands are only necessary once, in order to configure your system with the right credentials. There is no need to repeat these commands afterwards in case you just want to sign applications. The environment variables later in this guide will serve as a way to provide the necessary credentials instead. 178 | 179 | ### 2.3.2. Installing `signtool.exe` and Trusted Signing Dlib 180 | 181 | `signtool.exe` is the **_official_** code signing tools distributed by Microsoft with Windows SDKs. 182 | 183 | ⚠ You should assume that the required version of `signtool.exe` is _not_ installed on your system. On older versions, Azure Trusted Signing will not work, and will not show meaningful errors. Furthermore, the [official docs](https://learn.microsoft.com/en-us/azure/trusted-signing/how-to-signing-integrations) on minimum SDK requirements _contain the wrong version numbers_ so best to disregard them. So make sure to follow the installation instructions here. 184 | 185 | The minimum required version of signtool is _only_ included with Windows 11 SDK 10.0.22621.755 or higher, _or_ can be manually installed. We will manually install signtool using the [NuGet](https://www.nuget.org/downloads) package manager as is recommended: 186 | 187 | 1. Download `nuget.exe` from the [official site](https://www.nuget.org/downloads). 188 | 2. Open a command prompt and navigate to directory _where you want the signtool to be installed_. 189 | 3. Let's install both the correct `signtool.exe` as well as the Trusted Signing Dlib: 190 | ```dos 191 | nuget.exe install Microsoft.Windows.SDK.BuildTools -x 192 | nuget.exe install Microsoft.Trusted.Signing.Client 193 | ``` 194 | Replace `nuget.exe` with the actual path where the executable resides. 195 | 196 | The signtool should now be installed in a directory that is or starts with `Microsoft.Windows.SDK.BuildTools`. Make sure to locate the full path to the `signtool.exe`, e.g. `C:\sign\Microsoft.Windows.SDK.BuildTools\bin\10.0.26100.0\x64\signtool.exe`. 197 | 198 | The Trusted Signing Dlib should be installed in a directory that is or starts with `Microsoft.Trusted.Signing.Client` such as: `Microsoft.Trusted.Signing.Client.1.0.95`. Make sure to locate the `Azure.CodeSigning.Dlib.dll` file, e.g. `C:\sign\Microsoft.Trusted.Signing.Client.1.0.95\bin\x64\Azure.CodeSigning.Dlib.dll` and double check that the platform directory (`x86` or `x64`) matches with the signtool's path above. 199 | 200 | 💡 _Note down the absolute paths to `signtool.exe` and `Azure.CodeSigning.Dlib.dll`, as we will be using them below._ 201 | 202 | Finally, make sure the .NET 6.0 runtime is installed: 203 | 204 | * [.NET 6.0 runtime](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-6.0.9-windows-x64-installer). If this is not installed, signtool will fail silently without output. 205 | 206 | ### 2.3.3. Configuring signtool 207 | 208 | We now need to create a metadata configuration JSON file to make the signtool work with Azure Trusted Signing. This JSON file can be placed anywhere you like. 209 | 210 | Here, you will need the Azure Portal _region_ that you noted down before. 211 | 212 | * Create a `metadata.json` file with the following contents (replace details accordingly): 213 | ``` 214 | { 215 | "Endpoint": "", 216 | "CodeSigningAccountName": "", 217 | "CertificateProfileName": "" 218 | } 219 | ``` 220 | * Endpoint URL: choose according to the endpoint you've chosen for the Azure Trusted Signing: 221 | * East US (https://eus.codesigning.azure.net) 222 | * West US (https://wus.codesigning.azure.net) 223 | * West Central US (https://wcus.codesigning.azure.net) 224 | * West US 2 (https://wus2.codesigning.azure.net) 225 | * North Europe (https://neu.codesigning.azure.net) 226 | * West Europe (https://weu.codesigning.azure.net) 227 | 228 | 💡 _Note down the absolute path to `metadata.json`, as we will be using them below._ 229 | 230 | We also require a number of environment variables to be set. These can be added either to the system globally, or can be set in your own scripts calling the sign tool on your own accord. Environment variables can be set as follows (note that quotes are not necessary on Windows): 231 | ```dos 232 | set AZURE_TENANT_ID=... 233 | ``` 234 | 235 | Make sure the following environment variables are set and use the _tenant id_, _client id_ and _client secret_ from Azure Portal that you noted down before: 236 | 237 | * `AZURE_TENANT_ID`: The Microsoft Entra tenant (directory) ID. Use the value you noted down earlier. Can also be found in Microsoft Entra ID. 238 | * `AZURE_CLIENT_ID`: The client (application) ID of an App Registration in the tenant. Use the value you noted down earlier. 239 | * `AZURE_CLIENT_SECRET`: A client secret ("value") that was generated for the App Registration. Use the value you noted down earlier. 240 | 241 | In addition, this guide and its scripts below use a few custom environment variables of their own: 242 | 243 | * `ACS_DLIB` should point to the absolute filesystem path of the `Azure.CodeSigning.Dlib.dll` that was noted down. 244 | * `ACS_JSON` should point to the absolute filesystem path of the `metadata.json` file that was created above and noted down. 245 | 246 | All of the environment variables should be set in the command prompt in which you will be running signtool later, e.g.: 247 | ```dos 248 | set AZURE_TENANT_ID=00000000-0000-0000-0000-000000000000 249 | set AZURE_CLIENT_ID=00000000-0000-0000-0000-000000000000 250 | set AZURE_CLIENT_SECRET=... 251 | set ACS_DLIB=C:\sign\Microsoft.Trusted.Signing.Client.1.0.95\bin\x64\Azure.CodeSigning.Dlib.dll 252 | set ACS_JSON=C:\sign\metadata.json 253 | ``` 254 | 255 | ### 2.3.4. Testing `signtool.exe` 256 | 257 | We now need to make sure that `signtool.exe` is working and capable of using Azure Trusted Signing to sign executables, before doing anything else. 258 | 259 | Pick an executable that you would like to sign for testing purposes. We will sign this executable just to see if the entire signing flow works. 260 | 261 | In the command prompt that you have open, you run signtool accordingly, e.g.: 262 | 263 | ``` 264 | C:\sign\Microsoft.Windows.SDK.BuildTools\bin\10.0.26100.0\x64\signtool.exe sign /v /debug /fd SHA256 /tr "http://timestamp.acs.microsoft.com" /td SHA256 /dlib %ACS_DLIB% /dmdf %ACS_JSON% filetobesigned.exe 265 | ``` 266 | 267 | Make sure to use the absolute path to `signtool.exe` that you noted down earlier. Also replace the `filetobesigned.exe` with the executable that you want to sign. When you run this, you should immediately see messages involving Azure Trusted Signing, and your signing should be successful. 268 | 269 | If you are seeing a list of certificates or an error about no certificates that could be used, you are likely using the _wrong_ version of signtool, possibly one included with an SDK installed on your system. Make sure to only use the signtool that you installed above. 270 | 271 | If you are getting other errors, go through the guide again and make sure to double check every step. It is easy to make mistakes (e.g. typo's in the region URL) and almost every mistake will lead to a failure of signtool at this point. 272 | 273 | ### 2.3.4. Using `signtool.exe` with AAX `wraptool.exe` 274 | 275 | Now that signtool is successfully using Azure Trusted Signing to sign executables, we can now proceed to making signtool with Azure Trusted Signing work with PACE's wraptool. The PACE wraptool relies on signtool for its certificates, but as of the latest update of this guide _does not support_ the official Microsoft signtool with the Trusted Signing Dlib. It _does_ support the _unofficial_ AzureSignTool, but as mentioned before, this is not the focus of this guide. 276 | 277 | ⚠ This guide goes as far as _signing_ with the PACE wraptool, not including any _wrapping_. For wrapping, the arguments are very similar but your mileage may vary. 278 | 279 | ⚠ Newer PACE SDKs provide a `--explicitsigningoptions` option, which seemingly does not seem to be working just yet. 280 | 281 | It is necessary to work around the lack of PACE support by modifying the PACE wraptool. This works because the wraptool utility also relies on Microsoft's `signtool.exe` internally, and ProTools on Windows expects binaries to be signed with a whitelisted Microsoft certificate authority. 282 | 283 | The normal flow for wraptool relies on either a certificate file and password (no longer possible due to HSM) or a sign id (HSM) to passed in by the developer, with no apparent support for any other tools or options. However, we can use utility scripts and let the wrap tool use these instead to injects all the necessary arguments for Azure Trusted Signing to work. 284 | 285 | This section presents a stop-gap workaround while wraptools remains (partially) unsupported by PACE. 286 | 287 | In order for this solution to work, make sure: 288 | 289 | * Python 3 has been installed on the system. This is because the utility script below relies on it. 290 | * Choose a directory on the system that is accessible and where you can place the utility scripts. 291 | 292 | Now proceed by creating the utility scripts in the same folder: 293 | 294 | 1. Create a python file called `aax-signtool.py` with the following contents: 295 | ```python 296 | import sys 297 | import re 298 | 299 | # args.tmp should contain untouched CLI arguments 300 | args = None 301 | with open('args.tmp', 'r') as f: 302 | args = f.read() 303 | 304 | if args: 305 | with open('args.tmp', 'w') as f: 306 | # Filter and keep anything that starts with a C:\ path, discard any optional quotes and write back to file 307 | match = re.search(r'\"?(c\:\\.*?)\"?$', args, re.IGNORECASE) 308 | if match and match[1]: 309 | f.write(match[1]) 310 | exit(0) 311 | 312 | # Nothing to be done 313 | exit(1) 314 | ``` 315 | 316 | 2. Create a batch file called `aax-signtool.bat` with the following contents in a directory of your choice: 317 | ```dos 318 | @echo off 319 | 320 | :: KDSP Signtool wrapper for Eden SDK / AAX wraptool 321 | :: 322 | :: wraptool invokes signtool but makes a lot of assumptions about how we're going to sign 323 | :: which are incompatible with Azure Trusted Signing. 324 | :: 325 | :: This tool removes all its arguments and replaces it with the correct or necessary ones. 326 | :: Please adjust accordingly if necessary. 327 | :: 328 | :: Run Eden SDK's wraptool as follows: 329 | :: 330 | :: wraptool.exe sign --signtool signtool.bat --signid 1 --verbose --installedbinaries --account ... --password ... --wcguid ... --in ... 331 | :: 332 | :: signid 1 is bogus, but wraptool needs this nonsense in order to start up.. 333 | :: 334 | :: The following environment variables are necessary: 335 | :: 336 | :: SIGNTOOL_PATH 337 | :: ACS_DLIB (points to Dlib.dll file) 338 | :: ACS_JSON (points to the metadata.json file) 339 | :: AZURE_TENANT_ID (Microsoft Azure tenant ID) 340 | :: AZURE_CLIENT_ID (Microsoft Azure codesigning app client ID) 341 | :: AZURE_SECRET_ID (Microsoft Azure codesigning app secret value) 342 | :: 343 | 344 | :: Get script root dir, so we can find aax-signtool.py 345 | set root=%~dp0 346 | set root=%root:~0,-1% 347 | 348 | :: wraptool seems to mangle signtool's args and doesn't properly quote-escape the final binary path, 349 | :: and batch is not easy with string handling, so we use python to fix things up.. 350 | set args=%* 351 | echo %args%>args.tmp 352 | echo Patched signtool: Input arguments: %args% 353 | python "%root%\aax-signtool.py" 354 | set /p args=