Since February 1, 2017 the EV Code Signing can be considered as the minimum requirement for Code Signing. The certificates are installed on USB tokens and require drivers to operate. With the tool “Signtool.exe” from the Microsoft Windows SDK, it is usually no problem to interactively sign binaries. The manual intervention occurs as Signtool tries to access the certificate on the USB token and the security driver raises a popup dialog to enter the token password.
In a Continuous Integration/Continuous Delivery (CI/CD) build environment, most of the tasks to create a software product are automated and executed by unattended build agents. That means there is nobody interactively logged in at the agent. Such agents are often virtual machines without any physical monitor or keyboard. If EV Code Signing is needed, the build process will break or stop because no user will see the popup dialog.
The question “Automate Extended Validation (EV) code signing” at stackoverflow.com offers many solutions we will have a look at now:
1) Use driver option “Enable single logon”.
This is the favored answer from the Certificate Authorities. This still requires that a user logs in to the build agent, enters the password once and then locks the user session. If the user logs out after entering the password once, the user session is closed and the driver drops the password. That means that after every reboot of the OS, someone has to login to the agent before build processes can be executed successfully. This is a potential source of annoying errors.
2) Use a tool/script that detects the popup dialog and enters the password automatically.
This also requires that a user is logged in to the build agent. Otherwise there is no GUI context to show the dialog and the tool cannot detect it. This also means that manual preparation after a reboot of the build agent is needed.
3) Replace “Signtool.exe” with a program that can sign a file and unlock the USB token without manual intervention.
The answer from “draketb” at stackoverflow.com offers the source code to build “etokensign.exe” which takes similar information like “Signtool.exe” and the password to unlock the token. It also needs the container name of the certificate. Which is a hexadecimal string that must be extracted manually from the USB token.
The last proposal is the only one which needs no user login at the build agent. This solution runs totally unattended. But still, the need for the container name binds the build pipeline to the USB token. Of course you can use a simple script file on the build agent to break this dependency. You need then a individual script for every token. All the scripts must have the same name because the build pipeline should not need to differentiate on which build agent it is executed. This makes the solutions a little bit impracticable – or better more complex than expected.
That was the reason why I decided to modify the source code a little bit. The challenge was to identify the certificate by its name as it is done for “Signtool.exe” with the parameter “/n”.
Click the following link for the source code for “eTokenSign2” which contains some little changes to the source code from “draketb”:
The command line syntax of eTokenSign2.exe is
etokensign.exe <certificate name> <token PIN> <timestamp URL> <path to file to sign>
You can use the source code as it is. To create you own binary just follow the building steps at the end of the blog entry.
In our production environment the binary is wrapped with a script file. So only our IT administrators know the token passwords.
The successful signing can be verified in the properties of the signed files.
I hope this executable helps you to get your build processes running without the need of manual intervention 🙂
To build the binary follow these steps:
1- Download the zip file below and unzip it.
2- Install Visual Studio Community 2017 or the Visual Studio 2017 Build Tools
3- Open a “Developer Command Prompt”
4- Run “msbuild.exe eTokenSign2.vcxproj /p:Configuration=”Release” /p:Platform=x86″
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except where otherwise noted, this work is licensed under https://creativecommons.org/licenses/by-sa/4.0/.
It is a derivative work based on code from “draketb” at https://stackoverflow.com/a/47894907.