Automating code signing with signtool.exe, but without storing the certificate or password

user3466413 picture user3466413 · Sep 29, 2014 · Viewed 13.8k times · Source

I have a C#/.NET 4.5 x64 project in Visual Studio 2013. More than one developer works on this project, so the code is managed in Git. I'm signing the compiled .dlls and .exe with signtool.exe. My company bought a code signing certificate, and if I sign it manually from the command line like so:

signtool.exe sign /f cert.p12 /p "password" "compiled.dll"

...then it looks like everything's great: I get a success message and properties of the compiled DLL in Windows Explorer show it as properly signed. So, I have no problem with the actual signing process.

But, the certificate and its password must not live in Git. They will be provided out-of-band to all developers on the project. I can make the assumption that every developer when he's building the project will have the certificate stored in a predefined location on his computer and he'll know the password for it.

So, here's my question: how can I configure Visual Studio 2013 to automatically sign its compiled output without keeping the certificate or its password in Git? I want it to be as simple as, once the developer has the certificate in a predefined path (or imported, or whatever), and working on the assumption that the developer knows the password for the certificate, that clicking "Build" in Visual Studio 2013 just builds and signs it, no questions asked.

If the signing process can be non-interactive (no password prompt), that's a bonus. Eventually this will be part of a continuous integration (CI) server that may sign its output too, and because it's automated, nobody will be there to enter the password. However, I'll take any solution for now.

My certificate is a PKCS #12 format and is protected with a password. Windows claims it's not marked for export.

Answer

devstuff picture devstuff · Sep 30, 2014

A solution I've used before is similar to @Mikko's answer, but it's split into two pieces:

  1. A local non-controlled script that just sets an environment variable containing the password. This is the file you give to each developer.

    @echo off
    set SIGNPASS=whatever
    
  2. A source-controlled script that calls the previous script and the does the actual signing.

    @echo off
    setlocal
    call "C:\local\signing_password.bat"
    "C:\toolpath\signtool.exe" sign /f "c:\certpath\cert.p12" /p "%SIGNPASS%" "%1"
    endlocal
    

The setlocal/endlocal pair ensure that the password doesn't leak into the environment if the script is run manually.

The "%1" is the path to the executable passed as a script parameter in the Post Build step. ..