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_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_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_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 _extract_codepoints(self, filename_prefix, pem_file): x509cert = X509Certificate.from_pem_data(pem_file)[0] present_codepoints = [ rdn.get_value(self._EXPECT_PRESENT_CODEPOINT_OID).printable_value for rdn in x509cert.subject.get_all( self._EXPECT_PRESENT_CODEPOINT_OID) ] present_codepoints += [ rdn.get_value(self._EXPECT_PRESENT_CODEPOINT_OID).printable_value for rdn in x509cert.issuer.get_all( self._EXPECT_PRESENT_CODEPOINT_OID) ] codepoints = [] for codepoint_name in present_codepoints: if "#" in codepoint_name: continue try: getattr(JudgementCode, codepoint_name) except AttributeError: print("No such codepoint: %s (in %s)" % (codepoint_name, filename_prefix)) continue codepoints.append(codepoint_name) return codepoints
def get_tls_server_cert(cls, hostname, port=443): result = SubprocessExecutor([ cls._EXECUTABLE, "s_client", "-connect", "%s:%d" % (hostname, port), "-servername", hostname ]).run() certificates = X509Certificate.from_pem_data(result.stdout.decode()) return certificates[0]
def _recv_handshake(self, hooktype, msg_id, msg_type, data): print("<= %3d %s" % (msg_id, msg_type.name)) if msg_type == CertificatePkt: print(" %d certificates received:" % (len(data["payload"]["certificates"]))) for der_data in data["payload"]["certificates"]: cert = X509Certificate(bytes(der_data)) print(" %s" % (cert))
def test_der_input(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir(tempdir): crt = self._load_crt("ok/johannes-bauer-root") crt.write_derfile("root.der") output = self._run_x509sak([ "buildchain", "--inform", "der", "root.der" ]).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_failed_rsa_privkey(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir( tempdir), tempfile.NamedTemporaryFile(prefix="scrapeme_", suffix=".bin") as f: crt = self._load_crt("ok/johannes-bauer.com") self._prepare_file(f, [100, crt.der_data, 100]) self._run_x509sak(["scrape", "--keep-original-der", f.name]) scraped_crt = X509Certificate.read_derfile( "scrape/scrape_%07x_crt.der" % (100)) self.assertEqual(len(os.listdir("scrape/")), 1) self.assertEqual(crt, scraped_crt)
def test_forge_root(self): root_crt = self._load_crt("ok/johannes-bauer-root") with tempfile.TemporaryDirectory() as tempdir, WorkDir(tempdir): root_crt.write_pemfile("root.crt") self._run_x509sak(["forgecert", "root.crt"]) forged_root_crt = X509Certificate.read_pemfile("forged_00.crt")[0] self._assertCrtsSimilar(root_crt, forged_root_crt) orig_ski = root_crt.extensions.get_first( OIDDB.X509Extensions.inverse("SubjectKeyIdentifier")) forged_ski = forged_root_crt.extensions.get_first( OIDDB.X509Extensions.inverse("SubjectKeyIdentifier")) self.assertEqual(orig_ski, forged_ski)
def test_extract_nested(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir( tempdir), tempfile.NamedTemporaryFile(prefix="scrapeme_", suffix=".bin") as f: crt = self._load_crt("ok/johannes-bauer.com") self._prepare_file(f, [100, crt.der_data, 100]) self._run_x509sak(["scrape", "--extract-nested", f.name]) found = os.listdir("scrape/") self.assertEqual(len(found), 2) scraped_crt = X509Certificate.read_pemfile( "scrape/scrape_%07x_crt.pem" % (100))[0] scraped_pubkey = PublicKey.read_pemfile( "scrape/scrape_%07x_pubkey.pem" % (287))[0] self.assertEqual(scraped_crt.pubkey, scraped_pubkey)
def test_scrape_der_crt_twice(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir( tempdir), tempfile.NamedTemporaryFile(prefix="scrapeme_", suffix=".bin") as f: crt = self._load_crt("ok/johannes-bauer.com") self._prepare_file(f, [1000, crt.der_data, 100, crt.der_data, 500]) self._run_x509sak(["scrape", "--no-pem", f.name]) found = os.listdir("scrape/") self.assertEqual(len(found), 1) scraped_crt = X509Certificate.read_pemfile( "scrape/scrape_%07x_crt.pem" % (1000))[0] self.assertEqual(crt, scraped_crt) self._run_x509sak( ["scrape", "--force", "--allow-non-unique-blobs", f.name]) found = os.listdir("scrape/") self.assertEqual(len(found), 2) scraped_crt = X509Certificate.read_pemfile( "scrape/scrape_%07x_crt.pem" % (1000))[0] self.assertEqual(crt, scraped_crt) scraped_crt = X509Certificate.read_pemfile( "scrape/scrape_%07x_crt.pem" % (1100 + len(crt.der_data)))[0] self.assertEqual(crt, scraped_crt)
def test_scrape_pem_crt(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir( tempdir), tempfile.NamedTemporaryFile(prefix="scrapeme_", suffix=".bin") as f: crt = self._load_crt("ok/johannes-bauer.com") for prefix_len in [0, 100, 1000]: self._prepare_file( f, [prefix_len, crt.to_pem_data().encode("ascii"), 1000]) self._run_x509sak(["scrape", "--no-der", f.name]) found = os.listdir("scrape/") self.assertEqual(len(found), 1) scraped_crt = X509Certificate.read_pemfile( "scrape/scrape_%07x_crt.pem" % (prefix_len))[0] self.assertEqual(crt, scraped_crt) shutil.rmtree("scrape")
def test_scrape_der_crt(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir(tempdir): crt = self._load_crt("ok/johannes-bauer.com") for prefix_len in [ 0, 100, 1000, 1024 * 1024 - 100, 1024 * 1024, 1024 * 1024 + 100 ]: HashedPRNG(seed=b"foobar").write_bracketed( "out.bin", prefix_len, crt.der_data, 1000) self._run_x509sak(["scrape", "out.bin"]) found = os.listdir("scrape/") self.assertEqual(len(found), 1) scraped_crt = X509Certificate.read_pemfile( "scrape/scrape_%07x_crt.pem" % (prefix_len))[0] self.assertEqual(crt, scraped_crt) shutil.rmtree("scrape")
def test_forge_chain(self): root_crt = self._load_crt("ok/johannes-bauer-root") intermediate_crt = self._load_crt("ok/johannes-bauer-intermediate") server_crt = self._load_crt("ok/johannes-bauer.com") orig_crts = [root_crt, intermediate_crt, server_crt] with tempfile.TemporaryDirectory() as tempdir, WorkDir(tempdir): with open("chain.crt", "w") as f: for orig_crt in orig_crts: print(orig_crt.to_pem_data(), file=f) self._run_x509sak(["forgecert", "chain.crt"]) for (num, orig_crt) in enumerate(orig_crts): forged_crt = X509Certificate.read_pemfile("forged_%02d.crt" % (num))[0] self._assertCrtsSimilar(orig_crt, forged_crt)
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_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_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, expect_parse_failure=False): 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, ) # Plausibilize we're not chasing non-existing judgement codes -- don't # check the empty string because we often use that for debugging and # it's *obviously* wrong. if expect_present != ("", ): self.assertTrue( all( getattr(JudgementCode, codename, None) is not None for codename in expect_present)) if expect_absent != ("", ): self.assertTrue( all( getattr(JudgementCode, codename, None) is not None for codename in expect_absent)) if expect_parse_failure: with self.assertRaises(UnexpectedFileContentException): X509Certificate.from_pem_data( ResourceFileLoader.load_data(certname)) return certificates = X509Certificate.from_pem_data( ResourceFileLoader.load_data(certname)) crt_sources = [ CertificateAnalyzer.CertSource(crts=certificates, source="internal", source_type="pemcert") ] if parent_certname is not None: ca_certificate = CertificateAnalyzer.CertSource( crts=X509Certificate.from_pem_data( ResourceFileLoader.load_data(parent_certname)), source="internal", source_type="pemcert") else: ca_certificate = None analysis_params = { "fast_rsa": fast_rsa, "include_raw_data": include_raw, } if host_check is not None: analysis_params.update({ "entity_name": host_check, "purposes": ["tls-server"], }) elif purpose is not None: analysis_params["purposes"] = [purpose] cert_analyzer = CertificateAnalyzer(**analysis_params) analyses = cert_analyzer.analyze(crt_sources, ca_certificate) encountered_codes = CertificateAnalyzer.extract_codes_from_json( analyses) # If we're in debugging mode, update the consolidated JSON stat file if self._produce_statistics: self._update_stats_file(certname=certname, parent_certname=parent_certname, encountered_codes=encountered_codes, checked_codes=expect_present) for code in expect_present: self.assertIn(code, encountered_codes) for code in expect_absent: self.assertNotIn(code, encountered_codes)
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.")