How will Certificate Transparency Logs be Audited in Practice?

Certificate
Transparency, the effort to detect misissued SSL certificates by
publishing all certificates in public logs, only works if TLS clients
reject certificates that are not logged. Otherwise, certificate
authorities could just not log the certificates that they misissue.
TLS clients accomplish this by requiring that a certificate be accompanied
by a "signed certificate timestamp" (SCT), which is a promise by a log to
include the certificate within 24 hours of the SCT's issuance timestamp.
(This period is called the Maximum Merge Delay. It doesn't have to be
24 hours, but it is for all logs currently trusted by Chrome.) The SCT
can be embedded in the certificate, the OCSP response (which the TLS
server must staple), or the TLS handshake.

But an SCT is only a promise. What if the log breaks its promise and never
includes the certificate? After all, certificate authorities promise
not to issue bad certificates, but they do so in droves.
We don't want to replace the problem of untrustworthy certificate authorities with the
problem of untrustworthy Certificate Transparency logs. Fortunately,
Certificate Transparency was designed to be verifiable, making it
possible, in theory, for the TLS client to verify that the log fulfills
its promise. Unfortunately, SCT verification seems to be
a rather elusive problem in practice. In this post, I'm going to explore some of
the possible solutions, and explain their shortcomings.

Direct Proof Fetching

A Certificate Transparency log stores its certificates in the
leaves of an append-only Merkle Tree, which means the log can furnish
efficient-to-verify
cryptographic proofs that a certificate is included
in the tree, and that one tree is an appendage of another. The log
provides several HTTP endpoints for acquiring these proofs, which
a TLS client can use to audit an SCT as follows:

Use the get-sth
endpoint to retrieve the log's latest signed tree head (STH).
Store the returned tree head.

Use the get-sth-consistency
endpoint to retrieve a consistency proof between the tree represented by the previously-stored
tree head, and the tree represented by the latest tree head. Verify the proof. If the
proof is invalid, it means the new tree is not an appendage of the old tree,
so the log has violated its append-only property.

Use the get-proof-by-hash
endpoint to retrieve an inclusion proof for the SCT based on
the latest tree head. Verify the proof. If the proof is invalid, it means the log has not
included the corresponding certificate in the log.

Note that steps 1 and 2 only need to be done periodically for each log,
rather than once for every certificate validation.

There are several problems with direct proof fetching:

Logs can't handle the load of every web browser everywhere contacting them for every
TLS connection ever made.

When the client asks for an inclusion proof in step 3, it has to reveal to the log which
SCT it wants the proof for. Since each SCT corresponds to a certificate, and
certificates contain domain names, the log learns every domain the client is visiting,
which is a violation of the user's privacy.

Since the log has up to 24 hours to include a certificate, the certificate might
not be included at the time the client sees an SCT. Furthermore, even if
24 hours have elapsed, it would slow down the TLS client to retrieve
a proof during the TLS handshake. Therefore, the client has to store the SCT
and certificate and fetch the inclusion proof at some future time.

This exposes the client to denial-of-service attacks, wherein a malicious
website could try to exhaust the client's storage by spamming it with
certificates and SCTs faster than the client can audit them (imagine
a website which uses JavaScript to make a lot of AJAX requests in the
background). To avoid denial-of-service, the client has to limit the
size of its unverified SCT store. Once the limit is reached, the client
has to stop adding to the store, or evict old entries. Either way,
it exposes the client to flushing attacks, wherein an attacker with
a misissued certificate and bogus SCT spams the client with good
certificates and SCTs so the bad SCT never gets verified.

Another question is what to do if the verification fails. It's too
late to abort the TLS handshake and present a certificate error.
Most users would be terribly confused if their browser presented an error message
about a misbehaving log, so there needs to be a way for the client to
automatically report the SCT to some authority (e.g. the browser vendor) so they know
that the log has misbehaved and needs to be distrusted.

Proxied Auditing

To solve the scalability problem, clients can talk with servers
operated by the client software supplier, rather than the logs themselves.
(The client software supplier has to be comfortable operating
scalable infrastructure; Google is, at least.)

For example, Chrome doesn't retrieve STHs and consistency proofs directly
from logs. Instead, Google-operated servers perform steps 1 and 2
and distribute batches of STHs (called STHSets) to clients using Chrome's
update system. Users have to trust the Google servers to faithfully
audit the STHs, but since Chrome users already have to trust Google to
provide secure software, there is arguably no loss in security with this
approach.

DNS Proof Fetching

Chrome's solution to the privacy problem is to fetch inclusion proofs
over DNS.
Instead of making an HTTP request to the get-proof-by-hash endpoint, Chrome will make a series
of DNS requests for sub-domains of ct.googleapis.com which
contain the parameters of the inclusion proof request (e.g.
D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.pilot.ct.googleapis.com).
The name servers for ct.googleapis.com respond with the inclusion
proof inside TXT records.

Chrome believes DNS proof fetching is better for privacy because
instead of their servers learning the Chrome user's own IP address, they
will learn the IP address of the user's DNS resolver.
If the user is using an ISP's DNS resolver, its IP address will be
shared among all the ISP's users. Although DNS is unencrypted and
an eavesdropper along the network path could learn what inclusion proofs the
user is fetching, they would already know what domains the user is visiting
thanks to the DNS queries used to resolve the domain in the first place.

However, there are some caveats: if a user doesn't share a DNS resolver
with many other users, it may be possible to deanonymize them based on the timing
of the DNS queries. Also, if a user visits a domain handled
by an internal DNS server (e.g. www.intranet.example.com), that DNS query won't
leak onto the open Internet, but the DNS query for the inclusion proof will, causing
a DNS privacy leak that didn't exist previously. A privacy analysis is available
if you want to learn more.

Chrome's DNS proof fetching is still under development and hasn't shipped yet.

Embedded Proofs

The second version of Certificate Transparency
(which is not yet standardized or deployed) allows inclusion proofs to be presented to
clients alongside SCTs (embedded in the certificate, OCSP response, or TLS
handshake) saving the client the need to fetch inclusion proofs itself. That
solves the problems above, but creates new ones.

First, inclusion proofs can't be obtained until the certificate
is included in the log, which currently takes up to 24 hours.
If clients were to require inclusion proofs along with SCTs, a newly
issued certificate wouldn't be usable for up to 24 hours. That's OK for
renewals (as long as you don't wait until the last minute to renew), but
people are used to being able to get new certificates right away.

Second, clients can no longer choose the STH on which an inclusion
proof is based. With direct or DNS proof fetching, the client always
requests an inclusion proof to the latest STH, and the client can
easily verify that the latest STH is consistent with the previous STH.
When the client gets an embedded inclusion proof, it doesn't immediately
know if the STH on which it is based is consistent with other STHs
that the client has observed. The client has to audit the STH.

Unfortunately, the more frequently a log produces STHs that incorporate
recently-submitted certificates, the harder it is to audit them. Consider the extreme
case of a log creating a new STH immediately after every
certificate submission. Although this would let an inclusion proof be
obtained immediately for an SCT, auditing the new STH has all the
same problems as SCT auditing that were discussed above. It's bad for privacy,
since a log can assume that a client auditing a particular STH visited
the domain whose certificate was submitted right before the STH was produced.
And if the client wants to avoid making auditing requests during the TLS handshake,
it has to store the STH for later auditing, exposing it to denial-of-service and flushing
attacks.

STH Frequency and Freshness

To address the privacy problems of excessive STH production,
CTv2 introduces a new log attribute called the STH Frequency
Count, defined as the maximum number of STHs a log may produce
in any period equal to the Maximum Merge Delay. The CT gossip
draft defines a fresh STH to be one that was produced less than 14
days in the past. Clients could require that embedded inclusion proofs
be based on a fresh STH. Then, with an STH Frequency Count that permits
one STH an hour, there are only 336 fresh STHs at any given time for
any given log - few enough that auditing them is practical and private.
Auditing one of 336 STHs doesn't leak any information, and since the
number of STHs is bounded, there is no risk of denial-of-service or flushing
attacks.

It would also be possible for the client software supplier to operate a service
that continuously fetches fresh STHs from logs, audits them for consistency,
and distributes them to clients, saving clients the need to audit STHs themselves.
(Just like Chrome currently does with the latest STHs.)

Unfortunately, this is not a perfect solution.

First, there would still be a delay before an inclusion proof can be obtained
and a newly-issued certificate used. Many server operators and
certificate authorities aren't going to like that.

Second, server operators would need to refresh the embedded inclusion
proof every 14 days so it is always based on a fresh STH. That rules out
embedding the inclusion proof in the certificate, unless the certificate
is valid for less than 14 days. The server operator could use OCSP
stapling, with the certificate authority responsible for embedding a
new inclusion proof every 14 days in the OCSP response. Or the server
operator's software could automatically obtain a new inclusion
proof every 14 days and embed it in the TLS handshake. Unfortunately,
there are no implementations of the latter, and there are very few robust
implementations of OCSP stapling. Even if implementations existed,
there would be a very long tail of old servers that were never upgraded.

One possibility is to make DNS proof fetching the default,
but allow server operators to opt-in to embedded proofs, much
like server operators can use HSTS to opt-in to enforced HTTPS. Server
operators who run up-to-date software with
reliable OCSP Stapling and who don't mind a
delay in certificate issuance would be able to provide
better security and privacy to their visitors. Maybe at some
point in the distant future, embedded proofs could become
required for everyone.

All of this is a ways off. CTv2 is still not standardized.
Chrome still doesn't do any SCT auditing, and consequentially its CT policy
requires at least one SCT to be from a Google-operated log, since Google
obviously trusts its own logs not to break its promises. Fortunately, even without widespread log auditing, Certificate
Transparency has been a huge success, cleaning up the certificate authority
ecosystem and making everyone more secure. Nevertheless, I think it would be
a shame if Certificate Transparency's auditability were never fully realized,
and I hope we'll be able to find a way to make it work.

Comments

No comments yet.

Post a Comment

Your comment will be public. If you would like to contact me privately, please email me. Please keep your comment on-topic, polite, and comprehensible. Use the "Preview" button to make sure your comment is properly formatted. Name and email address are optional. If you specify an email address it will be kept confidential.