Update compile script to automatically sign windows executables

This commit is contained in:
Orsiris de Jong 2024-10-26 11:05:11 +02:00
parent 05f86eb6be
commit ccb1708ab4
4 changed files with 50 additions and 15 deletions

View file

@ -14,10 +14,11 @@ SET OLD_PYTHONPATH=%PYTHONPATH%
SET PYTHONPATH=c:\GIT\npbackup SET PYTHONPATH=c:\GIT\npbackup
"%PYTHON64%" -m pip install --upgrade -r npbackup/requirements.txt || exit 1 "%PYTHON64%" -m pip install --upgrade -r npbackup/requirements.txt || exit 1
"%PYTHON64%" bin\compile.py --audience all "%PYTHON64%" bin\compile.py --audience all --sign "C:\ODJ\KEYS\NetInventEV.dat"
"%PYTHON32%" -m pip install --upgrade -r npbackup/requirements.txt || exit 1 "%PYTHON32%" -m pip install --upgrade -r npbackup/requirements.txt || exit 1
"%PYTHON32%" bin\compile.py --audience all "%PYTHON32%" bin\compile.py --audience all --sign "C:\ODJ\KEYS\NetInventEV.dat"
SET PYTHONPATH=%OLD_PYTHONPATH% SET PYTHONPATH=%OLD_PYTHONPATH%

View file

@ -55,6 +55,7 @@ import glob
LICENSE_FILE = os.path.join(BASEDIR, os.pardir, "LICENSE") LICENSE_FILE = os.path.join(BASEDIR, os.pardir, "LICENSE")
NUITKA_STANDALONE_SUFFIX = ".dist"
del sys.path[0] del sys.path[0]
@ -183,7 +184,7 @@ def have_nuitka_commercial():
return False return False
def compile(arch: str, audience: str, build_type: str, onefile: bool, create_tar_only: bool, ev_cert_data: str = None): def compile(arch: str, audience: str, build_type: str, onefile: bool, create_tar_only: bool, ev_cert_data: str = None, sign_only: bool = False):
if build_type not in BUILD_TYPES: if build_type not in BUILD_TYPES:
print("CANNOT BUILD BOGUS BUILD TYPE") print("CANNOT BUILD BOGUS BUILD TYPE")
sys.exit(1) sys.exit(1)
@ -320,7 +321,7 @@ def compile(arch: str, audience: str, build_type: str, onefile: bool, create_tar
) )
errors = False errors = False
if not create_tar_only: if not create_tar_only and not sign_only:
print(CMD) print(CMD)
exit_code, output = command_runner(CMD, timeout=0, live_output=True) exit_code, output = command_runner(CMD, timeout=0, live_output=True)
if exit_code != 0: if exit_code != 0:
@ -334,7 +335,11 @@ def compile(arch: str, audience: str, build_type: str, onefile: bool, create_tar
print(f"COMPILED {'WITH SUCCESS' if not errors else 'WITH ERRORS'}") print(f"COMPILED {'WITH SUCCESS' if not errors else 'WITH ERRORS'}")
if os.name == "nt" and ev_cert_data: if os.name == "nt" and ev_cert_data:
sign(ev_cert_data=ev_cert_data, dry_run=args.dry_run) compiled_output_dir = os.path.join(
OUTPUT_DIR, "npbackup-{}{}".format(build_type, NUITKA_STANDALONE_SUFFIX)
)
npbackup_executable = os.path.join(compiled_output_dir, "npbackup-{}.exe".format(build_type))
sign(executable=npbackup_executable, arch=arch, ev_cert_data=ev_cert_data, dry_run=args.dry_run)
if not onefile: if not onefile:
if not create_archive( if not create_archive(
@ -354,11 +359,11 @@ def create_archive(
""" """
Create tar releases for each compiled version Create tar releases for each compiled version
""" """
nuitka_standalone_suffix = ".dist"
compiled_output = os.path.join( compiled_output = os.path.join(
output_dir, "npbackup-{}{}".format(build_type, nuitka_standalone_suffix) output_dir, "npbackup-{}{}".format(build_type, NUITKA_STANDALONE_SUFFIX)
) )
new_compiled_output = compiled_output[: -len(nuitka_standalone_suffix)] new_compiled_output = compiled_output[: -len(NUITKA_STANDALONE_SUFFIX)]
if os.path.isdir(new_compiled_output): if os.path.isdir(new_compiled_output):
shutil.rmtree(new_compiled_output) shutil.rmtree(new_compiled_output)
shutil.move(compiled_output, new_compiled_output) shutil.move(compiled_output, new_compiled_output)
@ -437,6 +442,23 @@ if __name__ == "__main__":
help="Digitally sign windows executables", help="Digitally sign windows executables",
) )
parser.add_argument(
"--sign-only",
action="store_true",
default=False,
required=False,
help="Only digitally sign built executables",
)
parser.add_argument(
"--dry-run",
action="store_true",
default=False,
required=False,
help="Dry run current action",
)
parser.add_argument( parser.add_argument(
"--create-tar-only", "--create-tar-only",
action="store_true", action="store_true",
@ -469,6 +491,7 @@ if __name__ == "__main__":
build_types = BUILD_TYPES build_types = BUILD_TYPES
create_tar_only = args.create_tar_only create_tar_only = args.create_tar_only
sign_only = args.sign_only
for audience in audiences: for audience in audiences:
npbackup_version = get_metadata(os.path.join(BASEDIR, "__version__.py"))[ npbackup_version = get_metadata(os.path.join(BASEDIR, "__version__.py"))[
@ -493,9 +516,10 @@ if __name__ == "__main__":
build_type=build_type, build_type=build_type,
onefile=args.onefile, onefile=args.onefile,
create_tar_only=create_tar_only, create_tar_only=create_tar_only,
ev_cert_data=args.ev_cert_data ev_cert_data=args.ev_cert_data,
sign_only=sign_only
) )
if not create_tar_only: if not create_tar_only and not sign_only:
audience_build = "private" if private_build else "public" audience_build = "private" if private_build else "public"
if result: if result:
print( print(

View file

@ -37,7 +37,7 @@ sys.path.insert(0, os.path.normpath(os.path.join(os.path.dirname(__file__), ".."
# Try to import a private key, if not available, fallback to the default key # Try to import a private key, if not available, fallback to the default key
try: try:
from PRIVATE._private_secret_keys import AES_KEY from PRIVATE._private_secret_keys import AES_KEY
from PRIVATE._private_obfuscation import obfuscation from PRIVATE._obfuscation import obfuscation
AES_KEY = obfuscation(AES_KEY) AES_KEY = obfuscation(AES_KEY)
IS_PRIV_BUILD = True IS_PRIV_BUILD = True

View file

@ -33,14 +33,14 @@ def check_private_ev():
Test if we have private ev data Test if we have private ev data
""" """
try: try:
from PRIVATE._private_ev_data import AES_EV_KEY from PRIVATE._ev_data import AES_EV_KEY
from PRIVATE._private_obfuscation import obfuscation from PRIVATE._obfuscation import obfuscation
print("We have private EV certifcate DATA") print("We have private EV certifcate DATA")
return obfuscation(AES_EV_KEY) return obfuscation(AES_EV_KEY)
except ImportError as exc: except ImportError as exc:
print("ERROR: Cannot load private EV certificate DATA: {}".format(exc)) print("ERROR: Cannot load private EV certificate DATA: {}".format(exc))
sys.exit() sys.exit(1)
def get_ev_data(cert_data_path): def get_ev_data(cert_data_path):
@ -64,7 +64,7 @@ def get_ev_data(cert_data_path):
return pkcs12_certificate, pkcs12_password, container_name, cryptographic_provider return pkcs12_certificate, pkcs12_password, container_name, cryptographic_provider
def sign(ev_cert_data: str = None, dry_run: bool = False): def sign(executable: str = None, arch: str = None, ev_cert_data: str = None, dry_run: bool = False):
if ev_cert_data: if ev_cert_data:
( (
pkcs12_certificate, pkcs12_certificate,
@ -81,6 +81,16 @@ def sign(ev_cert_data: str = None, dry_run: bool = False):
else: else:
signer = SignTool() signer = SignTool()
if executable:
print(f"Signing {executable}")
result = signer.sign(executable, bitness=arch, dry_run=dry_run)
if not result:
# IMPORTANT: If using an automated crypto USB EV token, we need to stop on error so we don't lock ourselves out of the token with bad password attempts
raise EnvironmentError(
"Could not sign executable ! Is the PKI key connected ?"
)
return result
for audience in audiences: for audience in audiences:
for arch in arches: for arch in arches:
for binary in binaries: for binary in binaries: