def verify_decode(self, test_vector, test_message): serialized = "".join(test_vector).decode("hex") message = test_message_pb2.TestMessage() tls_message.decode(serialized, message) self.assertEqual(test_message, message, msg = "%s vs %s" % (test_message, message))
def run(): """Fetch the proof for the supplied certificate.""" #TODO(eranm): Attempt fetching the SCT for this chain if none was given. if FLAGS.sct: cert_sct = client_pb2.SignedCertificateTimestamp() sct_data = open(FLAGS.sct, 'rb').read() if FLAGS.binary_sct: tls_message.decode(sct_data, cert_sct) else: cert_sct.ParseFromString(sct_data) sct_timestamp = cert_sct.timestamp print 'SCT for cert:', cert_sct else: sct_timestamp = FLAGS.timestamp constructed_leaf = construct_leaf_from_file(FLAGS.cert, sct_timestamp) leaf_hash = merkle.TreeHasher().hash_leaf(constructed_leaf) if FLAGS.verbose: print "Leaf hash: %s" % (leaf_hash.encode("hex")) (sth, proof) = fetch_single_proof(leaf_hash, FLAGS.log_url) if FLAGS.verbose: print "Leaf index in tree is %d, proof has %d hashes" % ( proof.leaf_index, len(proof.audit_path)) print "Audit path: %s" % ([t.encode('hex') for t in proof.audit_path]) verifier = merkle.MerkleVerifier() if verifier.verify_leaf_inclusion(constructed_leaf, proof.leaf_index, proof.audit_path, sth): print 'Proof verifies OK.'
def run(): """Fetch the proof for the supplied certificate.""" # TODO(eranm): Attempt fetching the SCT for this chain if none was given. if FLAGS.sct: cert_sct = client_pb2.SignedCertificateTimestamp() sct_data = open(FLAGS.sct, "rb").read() if FLAGS.binary_sct: tls_message.decode(sct_data, cert_sct) else: cert_sct.ParseFromString(sct_data) sct_timestamp = cert_sct.timestamp print "SCT for cert:", cert_sct else: sct_timestamp = FLAGS.timestamp constructed_leaf = construct_leaf_from_file(FLAGS.cert, sct_timestamp) leaf_hash = merkle.TreeHasher().hash_leaf(constructed_leaf) if FLAGS.verbose: print "Leaf hash: %s" % (leaf_hash.encode("hex")) (sth, proof) = fetch_single_proof(leaf_hash, FLAGS.log_url) if FLAGS.verbose: print "Leaf index in tree is %d, proof has %d hashes" % (proof.leaf_index, len(proof.audit_path)) print "Audit path: %s" % ([t.encode("hex") for t in proof.audit_path]) verifier = merkle.MerkleVerifier() if verifier.verify_leaf_inclusion(constructed_leaf, proof.leaf_index, proof.audit_path, sth): print "Proof verifies OK."
def verify_decode(self, test_vector, test_message): serialized = "".join(test_vector).decode("hex") message = test_message_pb2.TestMessage() tls_message.decode(serialized, message) self.assertEqual(test_message, message, msg = "%s vs %s" % (test_message, message))
def test_verify_embedded_scts_valid_signature(self): sct = client_pb2.SignedCertificateTimestamp() tls_message.decode(read_testdata_file('test-embedded-pre-cert.proof'), sct) result = self._test_verify_embedded_scts( ['test-embedded-cert.pem', 'ca-cert.pem']) self.assertEqual(result, [(sct, True)])
def decode_entry(entry): parsed_entry = client_pb2.ParsedEntry() tls_message.decode(entry.leaf_input, parsed_entry.merkle_leaf) parsed_entry.extra_data.entry_type = parsed_entry.merkle_leaf.timestamped_entry.entry_type tls_message.decode(entry.extra_data, parsed_entry.extra_data) return parsed_entry
def verify_sct(chain, sct_tls, log_key_pem): sct = client_pb2.SignedCertificateTimestamp() tls_message.decode(sct_tls, sct) log_key = pem.from_pem(log_key_pem, 'PUBLIC KEY')[0] key_info = verify.create_key_info_from_raw_key(log_key) lv = verify.LogVerifier(key_info) print lv.verify_sct(sct, chain)
def verify_sct(chain, sct_tls, log_key_pem): sct = client_pb2.SignedCertificateTimestamp() tls_message.decode(sct_tls, sct) log_key = pem.from_pem(log_key_pem, "PUBLIC KEY")[0] key_info = verify.create_key_info_from_raw_key(log_key) lv = verify.LogVerifier(key_info) print lv.verify_sct(sct, chain)
def decode_entry(entry): parsed_entry = client_pb2.ParsedEntry() tls_message.decode(entry.leaf_input, parsed_entry.merkle_leaf) parsed_entry.extra_data.entry_type = ( parsed_entry.merkle_leaf.timestamped_entry.entry_type) tls_message.decode(entry.extra_data, parsed_entry.extra_data) return parsed_entry
def verify_sct(c, sct_tls, log_key_pem): sct = client_pb2.SignedCertificateTimestamp() tls_message.decode(sct_tls, sct) key_info = client_pb2.KeyInfo() key_info.type = client_pb2.KeyInfo.ECDSA key_info.pem_key = log_key_pem lv = verify.LogVerifier(key_info) print lv.verify_sct(sct, c)
def verify_sct(chain, sct_tls, log_key_pem): sct = client_pb2.SignedCertificateTimestamp() tls_message.decode(sct_tls, sct) key_info = client_pb2.KeyInfo() key_info.type = client_pb2.KeyInfo.ECDSA key_info.pem_key = log_key_pem lv = verify.LogVerifier(key_info) print lv.verify_sct(sct, chain)
def dump_sctlist(sct_list): """Prints the proto representation of the SCTs contained in sct_list. Arguments: sct_list the packed SignedCertificateTransparencyList structure. """ tr = tls_message.TLSReader(sct_list) sctlist = client_pb2.SignedCertificateTimestampList() tr.read(sctlist) for s in sctlist.sct_list: sct = client_pb2.SignedCertificateTimestamp() tls_message.decode(s, sct) print sct
def test_verify_sct_valid_signature(self): test_cert = cert.Certificate.from_pem_file( os.path.join(FLAGS.testdata_dir, 'test-cert.pem')) sct = client_pb2.SignedCertificateTimestamp() tls_message.decode(read_testdata_file('test-cert.proof'), sct) key_info = client_pb2.KeyInfo() key_info.type = client_pb2.KeyInfo.ECDSA key_info.pem_key = read_testdata_file('ct-server-key-public.pem') verifier = verify.LogVerifier(key_info) self.assertTrue(verifier.verify_sct(sct, test_cert))
def dump_sctlist(sct_list): """Prints the proto representation of the SCTs contained in sct_list. Arguments: sct_list the packed SignedCertificateTransparencyList structure. """ tr = tls_message.TLSReader(sct_list) sctlist = client_pb2.SignedCertificateTimestampList() tr.read(sctlist) for s in sctlist.sct_list: sct = client_pb2.SignedCertificateTimestamp() tls_message.decode(s, sct) print(sct)
def test_verify_sth_for_bad_asn1_signature(self): # www.google.com certificate for which a bad SCT was issued. google_cert = ( '-----BEGIN CERTIFICATE-----', 'MIIEgDCCA2igAwIBAgIIdJ7+eILLLSgwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UE', 'BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl', 'cm5ldCBBdXRob3JpdHkgRzIwHhcNMTUxMDA3MTExMDM4WhcNMTYwMTA1MDAwMDAw', 'WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN', 'TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3', 'Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCR6Knj', 'TG6eyvY6C1VO7daC0AbWe3cenr9y9lVFQH2ej5r87znUvep4pC/bmG71aTd25wds', 'ScpclWNR4lkR9Ph45j8K+SjMXU7syiqFiWPWgVzyi4N3bXZw4w83RoTzfyUTn4Kx', '9nsQLmjVS4wUMSEpWBmYfORwUwMF8BYp5qSkIUogZTADPY7Qr8tmwEq8jLHv9z62', 'SiYd9JEcGdhnajgXg/+/f+iIb1jhkbjsTjFJBHClgrtRqLZHSU1THZCK6iULTd1B', '4yBNvXcHDaSBTPUSvZvZXo/msKfOqd0fHtny1icgl5CSU0tZrZPteomMnLMGdLlN', 'KHyqIX7XsAd3pNoXAgMBAAGjggFLMIIBRzAdBgNVHSUEFjAUBggrBgEFBQcDAQYI', 'KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE', 'XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0', 'MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G', 'A1UdDgQWBBSUPOkxr+tGC3JYs2JIdXVB2R+f8zAMBgNVHRMBAf8EAjAAMB8GA1Ud', 'IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMCEGA1UdIAQaMBgwDAYKKwYBBAHW', 'eQIFATAIBgZngQwBAgIwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3BraS5nb29n', 'bGUuY29tL0dJQUcyLmNybDANBgkqhkiG9w0BAQsFAAOCAQEAfBoIl5qeaJ7NZ6hB', 'WqeBZwbDV/DOHCPg3/84n8YGlfYdfXQpQdOWC5hfgEkkinBT0yp8dDTdXMUIT9Al', 'ZMrxE54xJ1cU6FPuZPDWOnzV+6YEW6P9RnTbqKgYCNkHFiFwVvFRm5RTEGei5TLv', 'l0zFDBusT/mgyvYBMIfW3vVPteEKKEz+aRCZHRiLAHbmJHj2+blVJeHGSF+eKN5q', 'GWgk7/pMww4JAXsLQ0mmL8qdJKivuiNcyyhbr8IeERiVcItKqfBsX1nwyUnYFWY3', 'HPkV+sXAPnpTGuxgYvTjcYDf8UO9lgDX5QubEFjjTuTIYAAabmc6Z4UKOS0O46Ne', 'z28m7Q==', '-----END CERTIFICATE-----') # The SCT with the bad signature. sct_bytes = ( '00ddeb1d2b7a0d4fa6208b81ad8168707e2e8e9d01d55c888d3d11c4cdb6ecbecc' '00000150421dfbb6000004030047304502200035de73784699d2ad8c3631aeda77' 'f70b2c899492b16f051fd6d38d46afc892022100a4d1b58c63002e5d0862a9f623' 'f67c8ccf5fc934bd28133fbc8f240aae4cab38' ).decode('hex') symantec_sct = client_pb2.SignedCertificateTimestamp() tls_message.decode(sct_bytes, symantec_sct) key_info = client_pb2.KeyInfo() key_info.type = client_pb2.KeyInfo.ECDSA key_info.pem_key = pem.to_pem( base64.decodestring(SYMANTEC_B64_KEY), 'PUBLIC KEY') verifier = verify.LogVerifier(key_info) self.assertRaises( error.SignatureError, verifier.verify_sct, symantec_sct, [cert.Certificate.from_pem("\n".join(google_cert)),])
def _test_verify_sct(self, proof, chain, fake_timestamp=None): sct = client_pb2.SignedCertificateTimestamp() tls_message.decode(read_testdata_file(proof), sct) if fake_timestamp is not None: sct.timestamp = fake_timestamp chain = map(lambda name: cert.Certificate.from_pem_file(os.path.join(FLAGS.testdata_dir, name)), chain) key_info = client_pb2.KeyInfo() key_info.type = client_pb2.KeyInfo.ECDSA key_info.pem_key = read_testdata_file("ct-server-key-public.pem") verifier = verify.LogVerifier(key_info) return verifier.verify_sct(sct, chain)
def _test_verify_sct(self, proof, chain, fake_timestamp = None): sct = client_pb2.SignedCertificateTimestamp() tls_message.decode(read_testdata_file(proof), sct) if fake_timestamp is not None: sct.timestamp = fake_timestamp chain = map(lambda name: cert.Certificate.from_pem_file( os.path.join(FLAGS.testdata_dir, name)), chain) key_info = client_pb2.KeyInfo() key_info.type = client_pb2.KeyInfo.ECDSA key_info.pem_key = read_testdata_file('ct-server-key-public.pem') verifier = verify.LogVerifier(key_info) return verifier.verify_sct(sct, chain)
def verify_embedded_scts(self, chain): """Extract and verify SCTs embedded in an X.509 certificate. Args: chain: list of cert.Certificate instances. Returns: List of (SignedCertificateTimestamp, bool) pairs, one for each SCT present in the certificate. The boolean is True if the corresponding SCT is valid, False otherwise. Raises: ct.crypto.error.EncodingError: failed to encode signature input, or decode the signature. ct.crypto.error.IncompleteChainError: the chain is empty. """ try: leaf_cert = chain[0] except IndexError: raise error.IncompleteChainError( "Chain must contain leaf certificate.") scts_blob = leaf_cert.embedded_sct_list() if scts_blob is None: return [] scts = client_pb2.SignedCertificateTimestampList() tls_message.decode(scts_blob, scts) result = [] for sct_blob in scts.sct_list: sct = client_pb2.SignedCertificateTimestamp() tls_message.decode(sct_blob, sct) try: self.verify_sct(sct, chain) result.append((sct, True)) except error.VerifyError: result.append((sct, False)) return result
def verify_embedded_scts(self, chain): """Extract and verify SCTs embedded in an X.509 certificate. Args: chain: list of cert.Certificate instances. Returns: List of (SignedCertificateTimestamp, bool) pairs, one for each SCT present in the certificate. The boolean is True if the corresponding SCT is valid, False otherwise. Raises: ct.crypto.error.EncodingError: failed to encode signature input, or decode the signature. ct.crypto.error.IncompleteChainError: the chain is empty. """ try: leaf_cert = chain[0] except IndexError: raise error.IncompleteChainError( "Chain must contain leaf certificate.") scts_blob = leaf_cert.embedded_sct_list() if scts_blob is None: return [] scts = client_pb2.SignedCertificateTimestampList() tls_message.decode(scts_blob, scts) result = [] for sct_blob in scts.sct_list: sct = client_pb2.SignedCertificateTimestamp() tls_message.decode(sct_blob, sct) try: self.verify_sct(sct, chain) result.append((sct, True)) except error.VerifyError: result.append((sct, False)) return result
def test_verify_embedded_scts_with_preca_valid_signature(self): sct = client_pb2.SignedCertificateTimestamp() tls_message.decode(read_testdata_file("test-embedded-with-preca-pre-cert.proof"), sct) result = self._test_verify_embedded_scts(["test-embedded-with-preca-cert.pem", "ca-cert.pem"]) self.assertEqual(result, [(sct, True)])