Certificate Transparency in Chrome

This page describes how to observe Chrome's CT state for a secure site.
This feature is available in Chrome 33, which currently (December 2013) is the unstable dev channel.

Basic UI indicator

This information is present in the Connection information pop-up in Chrome. Click the padlock:


Then navigate to the Connection Information tab:



The Certificate Transparency status is now a part of the website identity string. For example, when a valid Signed Certificate Timestamp accompanies the certificate, the string would read like so:


One of four strings will be displayed:
  • The identity of this website has been verified by ISSUER but does not have public audit records. - When no Signed Certificate Timestamps are present.
  • The identity of this website has been verified by ISSUER and is publicly auditable. - When a valid, verified Signed Certificate Timestamp is present.
  • The identity of this website has been verified by ISSUER, it claims to have public audit records, but the records cannot be verified. - When a Signed Certificate Timestamp from an unknown log is present.
  • The identity of this website has been verified by ISSUER, but its public audit records failed verification. - When a Signed Certificate Timestamp from a known log is present but failed to validate.

Detailed Signed Certificate Timestamp information

The exact Signed Certificate Timestamps Chrome sees and their validation status is available through Chrome's NetLog, accessible via chrome://net-internals.
The chrome NetLog should be opened before visiting a website:

After visiting the site for which CT information should be gathered, go back to the net-internals tab, fill in a description and click 'Save to file'.
The collected information will be downloaded as a json file.

The two event types of interest are SIGNED_CERTIFICATE_TIMESTAMPS_RECEIVED, showing raw SCTLists, and SIGNED_CERTIFICATE_TIMESTAMPS_CHECKED, showing parsed and checked SCTs.

For example, here's how to view these in Python:
import simplejson
r = simplejson.load(open('net-internals-log.json', 'r'))
CT_IDS = (r['constants']['logEventTypes']['SIGNED_CERTIFICATE_TIMESTAMPS_RECEIVED'],
r['constants']['logEventTypes']['SIGNED_CERTIFICATE_TIMESTAMPS_CHECKED'])
CT_EVENTS = [t for t in r['events'] if t['type'] in CT_IDS]
print CT_EVENTS


Will produce:
[{'phase': 0, 'source': {'type': 5, 'id': 2052}, 'type': 68, 'params': {'scts_from_ocsp_response': '', 'embedded_scts': 'AHcAdQCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAUIVYoohAAAEAwBGMEQCIGNwr7SiiTnLK7CW4qY/Q/j/pTasjmhNVEImhrGkH6ORAiAMiCcaaqbzYnPIUZrnfdgeVsHp1+bypQ2vZLWjAJN5aw==', 'scts_from_tls_extension': ''}, 'time': '3631894650'}, {'phase': 0, 'source': {'type': 5, 'id': 2052}, 'type': 69, 'params': {'unknown_logs_scts': [], 'invalid_scts': [], 'verified_scts': [{'origin': 'embedded_in_certificate', 'version': 0, 'log_id': 'pLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BA=', 'timestamp': '1383338248737', 'signature_data': 'MEQCIGNwr7SiiTnLK7CW4qY/Q/j/pTasjmhNVEImhrGkH6ORAiAMiCcaaqbzYnPIUZrnfdgeVsHp1+bypQ2vZLWjAJN5aw==', 'extensions': '', 'signature_algorithm': 'ECDSA', 'hash_algorithm': 'SHA256'}]}, 'time': '3631894650'}, {'phase': 0, 'source': {'type': 5, 'id': 2062}, 'type': 68, 'params': {'scts_from_ocsp_response': '', 'embedded_scts': '', 'scts_from_tls_extension': ''}, 'time': '3631894773'}, {'phase': 0, 'source': {'type': 5, 'id': 2062}, 'type': 69, 'params': {'unknown_logs_scts': [], 'invalid_scts': [], 'verified_scts': []}, 'time': '3631894773'}]

The first item on the list shows the raw list of embedded SCTs under the 'embedded_scts' key.
The second item contains the breakdown of all SCTs to three categories: SCTs from unknown logs, invalid SCTs and verified SCTs. The single SCT in this case is the embedded one which validated correctly.

Comments