Recipe Win Code Signing

matysek edited this page Nov 15, 2014 · 1 revision

Code-signing means attaching a digital signature to an executable to verify its vendor and the integrity of the file itself. More information can be found here. This article assumes that the reader is already familiar with code-signing executables on Windows.

Support in PyInstaller

PyInstaller does not sign executables itself: it only allows the generated executables to be signed without this damaging its functionality. It is not obvious that this works out of the box like with normal executables, because PyInstaller's executables are special (they have an attached package at the end of the executable itself).

Since PyInstaller allows a whole Python application, including all third-party dependencies, to be packaged into a single file, putting a digital signature on that file effectively mark the whole code of your application.

Integrating with PyInstaller's build process

If you are familiar with code-signing executables on the command-line, you know that you usually run the SIGNTOOL program from MS with a command line like this:

SIGNTOOL.EXE /F yourkey.pfx /P <password> /T <timestamping url> <file.exe>

This will work correctly with PyInstaller's generated executable. To achieve a broader integration, you can add this code-signing step to the .spec file, leveraging the fact that it is a regular Python file. The following is an example:

# -*- mode: python -*-

block_cipher = None


a = Analysis(['name.py'],
             pathex=[],
             hiddenimports=[],
             hookspath=None,
             runtime_hooks=None,
             cipher=block_cipher)
pyz = PYZ(a.pure,
          cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='name.exe',
          debug=True,
          strip=None,
          upx=False,
          console=True )


#######################################
# Code-sign the generated executable
import subprocess
subprocess.call([
   "SIGNTOOL.EXE",
   "/F", "path-to-key.pfx",
   "/P", "your-password",
   "/T", "time-stamping url",
   'name.exe',
])
#######################################

If you don't want to put your password in clear-text in the spec file, you can even use getpass.getpass() to ask it interactively to the user running the script.