def _test_examine_x509test_resultcode(self, certname, expect_present = None, expect_absent = None, parent_certname = None, fast_rsa = True, host_check = None, include_raw = False, purpose = None): if expect_present is None: expect_present = tuple() if not isinstance(expect_present, (list, tuple)): expect_present = (expect_present, ) if expect_absent is None: expect_absent = tuple() if not isinstance(expect_absent, (list, tuple)): expect_absent = (expect_absent, ) def gen_cmdline(fast_rsa, host_check, include_raw, certfile_name, cacertfile_name, outfile_name, outformat = "json"): cmdline = [ "examine" ] if fast_rsa: cmdline += [ "--fast-rsa" ] cmdline += [ "-f", outformat ] cmdline += [ "-o", outfile_name ] if cacertfile_name is not None: cmdline += [ "--parent-certificate", cacertfile_name ] if host_check is not None: cmdline += [ "-p", "tls-server", "--server-name", host_check ] elif purpose is not None: cmdline += [ "-p", purpose ] if include_raw: cmdline += [ "--include-raw-data" ] cmdline += [ certfile_name ] return cmdline with ResourceFileLoader(certname) as certfile, tempfile.NamedTemporaryFile(suffix = ".json") as outfile: if parent_certname is None: cmdline = gen_cmdline(fast_rsa, host_check, include_raw, certfile_name = certfile, cacertfile_name = None, outfile_name = outfile.name, outformat = "ansitext") self._run_x509sak(cmdline) cmdline = gen_cmdline(fast_rsa, host_check, include_raw, certfile_name = certfile, cacertfile_name = None, outfile_name = outfile.name, outformat = "json") self._run_x509sak(cmdline) else: with ResourceFileLoader(parent_certname) as parent_crt: cmdline = gen_cmdline(fast_rsa, host_check, include_raw, certfile_name = certfile, cacertfile_name = parent_crt, outfile_name = outfile.name, outformat = "ansitext") self._run_x509sak(cmdline) cmdline = gen_cmdline(fast_rsa, host_check, include_raw, certfile_name = certfile, cacertfile_name = parent_crt, outfile_name = outfile.name, outformat = "json") self._run_x509sak(cmdline) # Read all codes from the generated JSON with open(outfile.name) as f: data = json.load(f) encountered_codes = CertificateAnalyzer.extract_codes_from_json(data) for code in expect_present: self.assertIn(code, encountered_codes) for code in expect_absent: self.assertNotIn(code, encountered_codes)
def test_interm_root_notrust(self): with ResourceFileLoader("certs/ok/johannes-bauer-intermediate.pem") as certfile: self._run_x509sak([ "buildchain", certfile ], success_return_codes = [ 1 ]) output = self._run_x509sak([ "buildchain", "--allow-partial-chain", certfile ]).stdout self.assertOcurrences(output, b"-----BEGIN CERTIFICATE-----", 1) crts = X509Certificate.from_pem_data(output) self.assertEqual(crts[0].subject.rfc2253_str, "CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US") with ResourceFileLoader([ "certs/ok/johannes-bauer-root.pem" ], "certs/ok/johannes-bauer-intermediate.pem") as (searchdir, certfile): output = self._run_x509sak([ "buildchain", "-s", searchdir, certfile ]).stdout self.assertOcurrences(output, b"-----BEGIN CERTIFICATE-----", 2) crts = X509Certificate.from_pem_data(output.decode("ascii")) self.assertEqual(crts[0].subject.rfc2253_str, "CN=DST Root CA X3,O=Digital Signature Trust Co.") self.assertEqual(crts[1].subject.rfc2253_str, "CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US")
def test_multi_intermediate(self): with ResourceFileLoader("certs/ok/multi_intermediate/root.crt", "certs/ok/multi_intermediate/interm1.crt", "certs/ok/multi_intermediate/interm2.crt", "certs/ok/multi_intermediate/client.crt") as (root_file, interm1_file, interm2_file, client_file): # Assert that without any intermediate certificate, building a chain fails self._run_x509sak([ "buildchain", "-s", root_file, client_file ], success_return_codes = [ 1 ]) interm1_crt = X509Certificate.read_pemfile(interm1_file)[0] interm2_crt = X509Certificate.read_pemfile(interm2_file)[0] # With intermediate 1, it works. output = self._run_x509sak([ "buildchain", "-s", root_file, "-s", interm1_file, client_file ]).stdout certs = X509Certificate.from_pem_data(output) self.assertEqual(len(certs), 3) self.assertEqual(certs[1], interm1_crt) # Similarly, with intermedaite 2, it works. output = self._run_x509sak([ "buildchain", "-s", root_file, "-s", interm2_file, client_file ]).stdout certs = X509Certificate.from_pem_data(output) self.assertEqual(len(certs), 3) self.assertEqual(certs[1], interm2_crt) # But if both are accepted, intemediate 2 wins (it's newer) output = self._run_x509sak([ "buildchain", "-s", root_file, "-s", interm1_file, "-s", interm2_file, client_file ]).stdout certs = X509Certificate.from_pem_data(output) self.assertEqual(len(certs), 3) self.assertEqual(certs[1], interm2_crt)
def test_all_except_root(self): with ResourceFileLoader([ "certs/ok/johannes-bauer-root.pem", "certs/ok/johannes-bauer-intermediate.pem" ], "certs/ok/johannes-bauer.com.pem") as (searchdir, certfile): output = self._run_x509sak([ "buildchain", "-s", searchdir, "--outform", "all-except-root", certfile ]).stdout self.assertOcurrences(output, b"-----BEGIN CERTIFICATE-----", 2) crts = X509Certificate.from_pem_data(output.decode("ascii")) self.assertEqual(crts[0].subject.rfc2253_str, "CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US") self.assertEqual(crts[1].subject.rfc2253_str, "CN=johannes-bauer.com")
def test_render_multiple(self): with tempfile.NamedTemporaryFile( prefix="graph_", suffix=".dot") as f, ResourceFileLoader( "certs/ok/johannes-bauer.com.pem", "certs/ok/johannes-bauer-intermediate.pem", "certs/ok/johannes-bauer-root.pem") as certfiles: self._run_x509sak(["graph", "--outfile", f.name] + list(certfiles))
def test_all_except_root_stdout(self): with tempfile.NamedTemporaryFile(prefix = "chain_", suffix = ".pem") as outfile, ResourceFileLoader([ "certs/ok/johannes-bauer-root.pem", "certs/ok/johannes-bauer-intermediate.pem" ], "certs/ok/johannes-bauer.com.pem") as (searchdir, certfile): output = self._run_x509sak([ "buildchain", "-s", searchdir, "--outform", "all-except-root", "--outfile", outfile.name, certfile ]).stdout self.assertOcurrences(output, b"-----BEGIN CERTIFICATE-----", 0) crts = X509Certificate.read_pemfile(outfile.name) self.assertEqual(crts[0].subject.rfc2253_str, "CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US") self.assertEqual(crts[1].subject.rfc2253_str, "CN=johannes-bauer.com")
def test_storage_load_fails(self): with ResourceFileLoader( "certs/ok/johannes-bauer-root.pem") as cert_filename: pks = PrivateKeyStorage(PrivateKeyStorageForm.PEM_FILE, filename=cert_filename) with self.assertRaises(UnexpectedFileContentException): pks.load_private_key()
def test_eddsa_ed25519_privkey(self): with ResourceFileLoader( "privkey/ok/eddsa_ed25519.pem") as privkey_filename: privkey = EDPrivateKey.read_pemfile(privkey_filename)[0] self.assertIn("ed25519", str(privkey).lower()) self.assertEqual( privkey.priv, bytes.fromhex( "6da749b74428d3b57ffe0de0ace76e23205be1ac2d855c92a882fd3596116f95" )) self.assertFalse(privkey.prehash) self.assertEqual( privkey.scalar, 44908355547921110221441252462696832399707573104554503641423314681972008958608 ) self.assertEqual(privkey.cryptosystem.name, "ECC_EdDSA") pubkey = privkey.pubkey pubkey_point = pubkey.point self.assertTrue(pubkey_point.on_curve()) self.assertEqual( pubkey_point.encode(), bytes.fromhex( "dcbfc4d2bd9b5b9b3f7cd673cf559fe3793946a6a904355c07a552991bdba7c5" ))
def test_hash_search2(self): with ResourceFileLoader("certs/ok/johannes-bauer.com.pem") as infile: result = self._run_x509sak([ "hashpart", "-o", "100", "-l", "20", "-s", "0000", "-h", "sha1", "-h", "shake_256", infile ]) self.assertIn("b2736f6e448f6b6971a1e8ad5000009bf48752d1", result.stdout_text) self.assertIn("e96fe7bce088755d56506ab6238fd4c8a3a2cda6e9ddf9af58a0c79bebce02815c26731cad30bf0000b72acd5b5b5842", result.stdout_text) lines = result.stdout_text.split("\n")[:-1] self.assertEqual(len(lines), 2)
def test_render_dot_pdf(self): with tempfile.NamedTemporaryFile( prefix="graph_", suffix=".pdf") as f, ResourceFileLoader( "certs/ok/johannes-bauer.com.pem") as certfile: self._run_x509sak(["graph", "--outfile", f.name, certfile]) with open(f.name, "rb") as f: dotfile = f.read() self.assertTrue(dotfile.startswith(b"%PDF"))
def test_find_all(self): with ResourceFileLoader([ "certs/ok/johannes-bauer.com.pem", "certs/ok/johannes-bauer-root.pem", "certs/ok/pubkey_sig_ed25519.pem", "certs/ok/ecc_secp256r1.pem" ]) as srcdir: stdout = self._run_x509sak(["find", srcdir]).stdout self.assertOcurrences(stdout, b"BEGIN CERTIFICATE", 4)
def test_find_none(self): with ResourceFileLoader([ "certs/ok/johannes-bauer.com.pem", "certs/ok/johannes-bauer-root.pem", "certs/ok/pubkey_sig_ed25519.pem", "certs/ok/ecc_secp256r1.pem" ]) as srcdir: stdout = self._run_x509sak(["find", "-h", "abcdef112233", srcdir]).stdout self.assertEqual(b"", stdout)
def test_create_dot(self): with tempfile.NamedTemporaryFile( prefix="graph_", suffix=".dot") as f, ResourceFileLoader( "certs/ok/johannes-bauer.com.pem") as certfile: self._run_x509sak(["graph", "--outfile", f.name, certfile]) with open(f.name) as f: dotfile = f.read() self.assertIn("digraph", dotfile) self.assertIn("bcade7ce", dotfile)
def test_examine_write_json(self): with ResourceFileLoader("certs/ok/custom_key_usage.pem") as crtfile, tempfile.NamedTemporaryFile(prefix = "crt_", suffix = ".json") as jsonfile: self._run_x509sak([ "examine", "-f", "json", "-o", jsonfile.name, crtfile ]) with open(jsonfile.name) as jsonfile: json_data = json.load(jsonfile) self.assertEqual(json_data["data"][0]["issuer"]["rfc2253"], "CN=Root CA") self.assertEqual(json_data["data"][0]["subject"]["rfc2253"], "CN=0b239049-3d65-46c2-8fdd-90f13cadc70b") self.assertEqual(json_data["data"][0]["validity"]["not_before"]["iso"], "2018-07-14T16:00:53Z") self.assertEqual(json_data["data"][0]["validity"]["not_after"]["iso"], "2019-07-14T16:00:53Z")
def test_storage_load_key_der(self): with ResourceFileLoader("privkey/ok/ecc_secp256r1.der", "privkey/ok/eddsa_ed25519_rfc8032.der", "privkey/ok/rsa_768.der") as privkey_filenames: for privkey_filename in privkey_filenames: pks = PrivateKeyStorage(PrivateKeyStorageForm.DER_FILE, filename=privkey_filename) privkey = pks.load_private_key() self.assertIsInstance( privkey, (RSAPrivateKey, ECPrivateKey, EDPrivateKey))
def test_multifile_all_except_root(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir(tempdir), ResourceFileLoader([ "certs/ok/johannes-bauer-root.pem", "certs/ok/johannes-bauer-intermediate.pem" ], "certs/ok/johannes-bauer.com.pem") as (searchdir, certfile): self._run_x509sak([ "buildchain", "-s", searchdir, "--outform", "multifile", "--outfile", "outcrt%02d.pem", certfile ]) self.assertEqual(X509Certificate.read_pemfile("outcrt00.pem")[0].subject.rfc2253_str, "CN=DST Root CA X3,O=Digital Signature Trust Co.") self.assertEqual(X509Certificate.read_pemfile("outcrt01.pem")[0].subject.rfc2253_str, "CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US") self.assertEqual(X509Certificate.read_pemfile("outcrt02.pem")[0].subject.rfc2253_str, "CN=johannes-bauer.com") self._run_x509sak([ "buildchain", "-s", searchdir, "--outform", "multifile", "--order-leaf-to-root", "--outfile", "rev_outcrt%02d.pem", certfile ]) self.assertEqual(X509Certificate.read_pemfile("rev_outcrt00.pem")[0].subject.rfc2253_str, "CN=johannes-bauer.com") self.assertEqual(X509Certificate.read_pemfile("rev_outcrt01.pem")[0].subject.rfc2253_str, "CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US") self.assertEqual(X509Certificate.read_pemfile("rev_outcrt02.pem")[0].subject.rfc2253_str, "CN=DST Root CA X3,O=Digital Signature Trust Co.")
def test_render_unknown_ext(self): with tempfile.NamedTemporaryFile( prefix="graph_", suffix=".xyz") as f, ResourceFileLoader( "certs/ok/johannes-bauer.com.pem") as certfile: self._run_x509sak(["graph", "--outfile", f.name, certfile], success_return_codes=[1]) self._run_x509sak( ["graph", "--outfile", f.name, "--format", "pdf", certfile]) with open(f.name, "rb") as f: dotfile = f.read() self.assertTrue(dotfile.startswith(b"%PDF"))
def test_find_specific(self): with ResourceFileLoader([ "certs/ok/johannes-bauer.com.pem", "certs/ok/johannes-bauer-root.pem", "certs/ok/pubkey_sig_ed25519.pem", "certs/ok/ecc_secp256r1.pem" ]) as srcdir: stdout = self._run_x509sak(["find", "-h", "853e", srcdir]).stdout self.assertIn( b"853ecf1f70c5f7db4d3883f3f217a9a06ec29445839e9c6acbcf69a399ecaea9", stdout) self.assertOcurrences(stdout, b"BEGIN CERTIFICATE", 1)
def test_pkcs12_passphrase_specify(self): with tempfile.NamedTemporaryFile(mode = "w", suffix = ".txt") as passfile, ResourceFileLoader("certs/ok/ecc_secp256r1.pem", "privkey/ok/ecc_secp256r1.pem") as (certfile, keyfile): print("foobar", file = passfile) passfile.flush() pkcs12 = self._run_x509sak([ "buildchain", "--outform", "pkcs12", "--private-key", keyfile, "--pkcs12-passphrase-file", passfile.name, certfile ]).stdout # Fails with wrong passphrase SubprocessExecutor([ "openssl", "pkcs12", "-passin", "-nodes", "pass:"******"openssl", "pkcs12", "-passin", "-nodes", "pass:abcdef" ], stdin = pkcs12, success_return_codes = [ 1 ]).run() # Works with right passphrase output = SubprocessExecutor([ "openssl", "pkcs12", "-nodes", "-passin", "pass:foobar" ], stdin = pkcs12).run().stdout self.assertOcurrences(output, b"-----BEGIN CERTIFICATE-----", 1) self.assertOcurrences(output, b"-----BEGIN PRIVATE KEY-----", 1)
def test_pkcs12_passphrase_autogen(self): with ResourceFileLoader("certs/ok/ecc_secp256r1.pem", "privkey/ok/ecc_secp256r1.pem") as (certfile, keyfile): result = self._run_x509sak([ "buildchain", "--outform", "pkcs12", "--private-key", keyfile, certfile ]) pkcs12 = result.stdout stderr = result.stderr_text.rstrip("\r\n") self.assertTrue(stderr.startswith("Passphrase: ")) passphrase = stderr[12:] # Fails with wrong passphrase SubprocessExecutor([ "openssl", "pkcs12", "-passin", "-nodes", "pass:"******"openssl", "pkcs12", "-passin", "-nodes", "pass:abcdef" ], stdin = pkcs12, success_return_codes = [ 1 ]).run() # Works with right passphrase output = SubprocessExecutor([ "openssl", "pkcs12", "-nodes", "-passin", "pass:"******"-----BEGIN CERTIFICATE-----", 1) self.assertOcurrences(output, b"-----BEGIN PRIVATE KEY-----", 1)
def test_encodings(self): with ResourceFileLoader("certs/ok/johannes-bauer-intermediate.pem") as crtfile: self._run_x509sak([ "examine", "-p", "ca", "--fast-rsa", "-f", "ansitext", crtfile ]) self._run_x509sak([ "examine", "-p", "ca", "--fast-rsa", "-f", "text", crtfile ]) self._run_x509sak([ "examine", "-p", "ca", "--fast-rsa", "-f", "json", crtfile ])
def test_hash_search1(self): with ResourceFileLoader("certs/ok/johannes-bauer.com.pem") as infile: result = self._run_x509sak([ "hashpart", "-o", "20", "-l", "20", "-s", "af620e0", "-h", "md5", infile ]) self.assertIn("602223a041eaf620e00527d2c0a8cb31", result.stdout_text) lines = result.stdout_text.split("\n")[:-1] self.assertEqual(len(lines), 1)
def test_root_notrust(self): with ResourceFileLoader("certs/ok/johannes-bauer-root.pem") as certfile: output = self._run_x509sak([ "buildchain", "--dont-trust-crtfile", certfile ]).stdout self.assertOcurrences(output, b"-----BEGIN CERTIFICATE-----", 1) crts = X509Certificate.from_pem_data(output) self.assertEqual(crts[0].subject.rfc2253_str, "CN=DST Root CA X3,O=Digital Signature Trust Co.")
def test_purpose_tls_server(self): with ResourceFileLoader("certs/ok/johannes-bauer.com.pem") as crtfile: output = self._run_x509sak([ "examine", "-p", "tls-server", "-n", "johannes-bauer.com", crtfile ]).stdout_text self.assertIn("Subject Alternative Name matches 'johannes-bauer.com'", output)
def test_pkcs12_stdout(self): with ResourceFileLoader([ "certs/ok/johannes-bauer-root.pem", "certs/ok/johannes-bauer-intermediate.pem" ], "certs/ok/johannes-bauer.com.pem") as (searchdir, certfile): pkcs12 = self._run_x509sak([ "buildchain", "-s", searchdir, "--outform", "pkcs12", certfile ]).stdout output = SubprocessExecutor([ "openssl", "pkcs12", "-passin", "pass:"******"-----BEGIN CERTIFICATE-----", 3)
def test_pkcs12(self): with tempfile.NamedTemporaryFile(suffix = ".p12") as p12file, ResourceFileLoader([ "certs/ok/johannes-bauer-root.pem", "certs/ok/johannes-bauer-intermediate.pem" ], "certs/ok/johannes-bauer.com.pem") as (searchdir, certfile): self._run_x509sak([ "buildchain", "-s", searchdir, "--outform", "pkcs12", "--outfile", p12file.name, certfile ]) output = SubprocessExecutor([ "openssl", "pkcs12", "-in", p12file.name, "-passin", "pass:"******"-----BEGIN CERTIFICATE-----", 3)
def test_simple_hash(self): with ResourceFileLoader("certs/ok/johannes-bauer.com.pem") as infile: result = self._run_x509sak([ "hashpart", "-l", "3", "-h", "md5", infile ]) self.assertIn("cfab1ba8c67c7c838db98d666f02a132", result.stdout_text) # md5("--") lines = result.stdout_text.split("\n")[:-1] self.assertEqual(len(lines), 6)
def test_purpose_ca(self): with ResourceFileLoader("certs/ok/johannes-bauer-root.pem") as crtfile: self._run_x509sak([ "examine", "-p", "ca", "--fast-rsa", crtfile ])
def test_root_only_out_rootonly(self): with ResourceFileLoader([ "certs/ok/johannes-bauer-root.pem", "certs/ok/johannes-bauer-intermediate.pem" ], "certs/ok/johannes-bauer.com.pem") as (searchdir, certfile): output = self._run_x509sak([ "buildchain", "-s", searchdir, "--outform", "rootonly", certfile ]).stdout self.assertOcurrences(output, b"-----BEGIN CERTIFICATE-----", 1) crts = X509Certificate.from_pem_data(output.decode("ascii")) self.assertEqual(crts[0].subject.rfc2253_str, "CN=DST Root CA X3,O=Digital Signature Trust Co.")
def test_rsa_pss_custom(self): with ResourceFileLoader("certs/ok/rsapss_sha256_salt_32.pem") as crtfile: self._run_x509sak([ "examine", "-p", "tls-client", "--fast-rsa", "-f", "json", crtfile ]).stdout_json