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 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 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) 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 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 setUp(self): sct_proto = client_pb2.SignedCertificateTimestamp() sct_proto.version = client_pb2.V1 sct_proto.id.key_id = ( "a4b90990b418581487bb13a2cc67700a3c359804f91bdfb8e377cd0ec80ddc10" ).decode('hex') sct_proto.timestamp = 1365427532443 sct_proto.signature.hash_algorithm = client_pb2.DigitallySigned.SHA256 sct_proto.signature.sig_algorithm = client_pb2.DigitallySigned.ECDSA sct_proto.signature.signature = ( "304502210089de897f603e590b1aa0d7c4236c2f697e90602795f7a469215fda5e" "460123fc022065ab501ce3dbaf49bd563d1c9ff0ac76120bc11f65a44122b3cd8b" "89fc77a48c").decode("hex") self._sct_proto = sct_proto
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 _parse_sct(self, sct_response): sct_data = json.loads(sct_response) try: sct = client_pb2.SignedCertificateTimestamp() sct_version = sct_data["sct_version"] if sct_version != 0: raise InvalidResponseError( "Unknown SCT version: %d" % sct_version) sct.version = client_pb2.V1 sct.id.key_id = base64.b64decode(sct_data["id"]) sct.timestamp = sct_data["timestamp"] hash_algorithm, sig_algorithm, sig_data = verify.decode_signature( base64.b64decode(sct_data["signature"])) sct.signature.hash_algorithm = hash_algorithm sct.signature.sig_algorithm = sig_algorithm sct.signature.signature = sig_data return sct except KeyError as e: raise InvalidResponseError("SCT Missing field: %s" % e)
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_correctly_encodes_sct_list_multiple_scts(self): first_sct = tls_message.encode(self._sct_proto) sct_proto_2 = client_pb2.SignedCertificateTimestamp() sct_proto_2.CopyFrom(self._sct_proto) sct_proto_2.timestamp = 1365427530000 second_sct = tls_message.encode(sct_proto_2) sct_list = client_pb2.SignedCertificateTimestampList() sct_list.sct_list.extend([first_sct, second_sct]) encoded_sct_list = tls_message.encode(sct_list) # First 2 bytes are list length prefix - 240 bytes in total # Next 2 bytes are the length of the first SCT: 118 self.assertEqual(encoded_sct_list[:4], "00f00076".decode("hex")) first_sct_end = len(first_sct) + 4 # The actual SCT self.assertEqual(encoded_sct_list[4:first_sct_end], first_sct) # Next 2 bytes are the length of the second SCT (118 again) self.assertEqual(encoded_sct_list[first_sct_end:first_sct_end + 2], "0076".decode("hex")) # The 2nd SCT self.assertEqual(encoded_sct_list[first_sct_end + 2:], second_sct)
def read_sct_from_file(sct_file): cert_sct = client_pb2.SignedCertificateTimestamp() cert_sct.ParseFromString(open(sct_file, 'rb').read()) return cert_sct