Custom Keys with Authenticode Signing
The only official way to Authenticode sign a file on Windows is using the very flexible “signtool” as part of the Windows SDK. Signtool is capable of signing a variety of things, such as portable executables, MSIs, etc with a variety of different digest algorithms, timestamps, and the like.
One area of signtool that has not been flexible is where it looks for the private key to perform the signature. If the private key was not associated to a certificate in the certificate store, signtool would be unable to use this.
This meant that the private key needed support from CAPI or CNG. If the private key was not reachable through a CSP or CNG Store Provider, then sign tool would not be able to use the key. For the most part, this was OK. Most SmartCard and HSM vendors provide a CSP and/or CNG Provider, so signtool worked fine.
Sometimes though, a CNG or CSP provider is not available. A practical case for this is Azure Key Vault. In this situation, using signtool was not possible, until recently.
Starting in the Windows 10 SDK, two new command line switches are available,
dg
and di
. Recall that a signature is always performed on a hash on
Authenticode. The dg
option changes signtool’s behavior to output a digest
that you can sign using anything you’d like. Let’s try this on a copy of
notepad.exe.
signtool sign /dg "C:\scratch\dir" /fd SHA256 /f public-cert.cer notepad.exe
This takes a file to a public certificate - there is no key in
public-cert.cer. You could also use the /sha1
option to specify a certificate
in the certificate store that also has only a public key. This will output a few
files in the “C:\scratch\dir” directory. The digest is the one with the “.dig”
extension. This file will have the Base64 encoded digest to sign. Next, using
your custom tool, sign the digest with the private key for the certificate. You
should decode the Base64 signature before signing if the signing API expects a
raw binary digest.
Next, encode your signature in base64 and place it in a file in the “C:\scratch\dir” directory with the same name as the digest file, with the “signed” extension. For example, “notepad.exe.dig.signed”.
The next step is to ingest the signed digest along with the rest of the Authenticode signature to complete the signing.
signtool sign /di "C:\scratch\dir" notepad.exe
This will complete the signing process, and we now have our own signed copy of
notepad.exe. Appending a signature is done just as before, except with the /as
flag.
This provides great flexibility for signers to use non CSP / CNG signing
options, or offloading the signing process. Signtool can now also sign just
a plain digest file using the /ds
option. If you have a dedicated server for
performing Authenticode signing, you can now use the /dg
, /ds
, /di
options
so that only a very small file needs to be moved to the signing server, instead
of the entirely binary if they are large in size.