def test_timestamp_old(test_file, digest_algo, tmp_path, signing_keys, httpserver): """Verify that we can sign with old style timestamps.""" signed_exe = tmp_path / "signed.exe" priv_key = load_private_key(open(signing_keys[0], "rb").read()) certs = load_pem_certs(signing_keys[1].read_bytes()) def signer(digest, digest_algo): return sign_signer_digest(priv_key, digest_algo, digest) httpserver.serve_content( (DATA_DIR / f"unsigned-{digest_algo}-ts-old.dat").read_bytes()) assert sign_file( test_file, signed_exe, digest_algo, certs, signer, timestamp_style="old", # Comment this out to use a real timestamp server so that we can # capture a response timestamp_url=httpserver.url, ) # Check that we have 3 certificates in the signature if is_pefile(test_file): with signed_exe.open("rb") as f: certificates = get_certificates(f) sigs = get_signatures_from_certificates(certificates) assert len(certificates) == 1 assert len(sigs) == 1 assert len(sigs[0]["certificates"]) == 3 assert verify_pefile(f)
def get_dummy_signature(infile, digest_algo, url=None, comment=None, crosscert=None): """Sign a file using dummy keys. This is useful as a way to get the structure of a signature, without having to create it from scratch. The dummy signature will also include relevent Authenticode specific checksums. Args: infile (str): Path to the file to generate a dummy signature for digest_algo (str): What digest algorithm to use. Should be one of 'sha1', or 'sha256' url (str): A URL to embed into the signature comment (str): A string to embed into the signature crosscert (str): Extra certificates to attach to the signature Returns: bytes of the dummy signature as a DER encoded ASN.1 structure """ with tempfile.TemporaryDirectory() as d: d = Path(d) cert_file = d / "cert.pem" cert_file.write_text(DUMMY_KEY) infile = Path(infile) dest = d / ("signed1" + infile.suffix) run_sign_command( infile, dest, cert_file, cert_file, digest_algo, url=url, comment=comment, crosscert=crosscert, ) sig = d / "signature" extract_signature(dest, sig) if is_pefile(infile): pefile_cert = certificate.parse(sig.read_bytes()) return pefile_cert.data else: return sig.read_bytes()
def test_timestamp_rfc3161(test_file, digest_algo, tmp_path, signing_keys, httpserver): """Verify that we can sign with RFC3161 timestamps.""" signed_exe = tmp_path / "signed.exe" priv_key = load_private_key(open(signing_keys[0], "rb").read()) certs = load_pem_certs(signing_keys[1].read_bytes()) def signer(digest, digest_algo): return sign_signer_digest(priv_key, digest_algo, digest) httpserver.serve_content( (DATA_DIR / f"unsigned-{digest_algo}-ts-rfc3161.dat").read_bytes()) assert sign_file( test_file, signed_exe, digest_algo, certs, signer, timestamp_style="rfc3161", # Comment this out to use a real timestamp server so that we can # capture a response timestamp_url=httpserver.url, ) # Check that we have 1 certificate in the signature, # and have a counterSignature section if is_pefile(test_file): with signed_exe.open("rb") as f: certificates = get_certificates(f) sigs = get_signatures_from_certificates(certificates) assert len(certificates) == 1 assert len(sigs) == 1 assert len(sigs[0]["certificates"]) == 1 assert any((sigs[0]["signerInfos"][0]["unauthenticatedAttributes"] [i]["type"] == id_timestampSignature) for i in range( len(sigs[0]["signerInfos"][0] ["unauthenticatedAttributes"]))) assert verify_pefile(f)
def test_sign_file(test_file, digest_algo, tmp_path, signing_keys): """Check that we can sign with the osslsign wrapper.""" signed_exe = tmp_path / "signed.exe" priv_key = load_private_key(open(signing_keys[0], "rb").read()) certs = load_pem_certs(signing_keys[1].read_bytes()) def signer(digest, digest_algo): return sign_signer_digest(priv_key, digest_algo, digest) assert sign_file(test_file, signed_exe, digest_algo, certs, signer) # Check that we have 1 certificate in the signature if test_file in TEST_PE_FILES: assert is_pefile(test_file) with signed_exe.open("rb") as f: certificates = get_certificates(f) sigs = get_signatures_from_certificates(certificates) assert len(certificates) == 1 assert len(sigs) == 1 assert len(sigs[0]["certificates"]) == 1 assert verify_pefile(f)
def write_signature(infile, outfile, sig): """Writes a signature into a file. Args: infile (str): Path to the unsigned file outfile (str): Path to write the signature into sig (str): bytes of signature to add into the file Returns: Same as `winsign.sign.osslsigncode`_ """ # PE files need their signatures encapsulated if is_pefile(infile): padlen = (8 - len(sig) % 8) % 8 sig += b"\x00" * padlen cert = certificate.build({ "size": len(sig) + 8, "revision": "REV2", "certtype": "PKCS7", "data": sig }) else: cert = sig with tempfile.NamedTemporaryFile() as sigfile: sigfile.write(cert) sigfile.flush() cmd = [ "attach-signature", "-sigin", sigfile.name, "-in", infile, "-out", outfile, ] osslsigncode(cmd)