20151129 Time over HTTPS specification

I have worked more on the “time over HTTPS” idea I proposed some weeks ago.

As I mentioned, there are a parliament of political issues [1] with suddenly starting to pull time from HTTPS servers.

To take the most fundamental: What if the HTTPS server owner doesn’t want to supply time ?

It follows quite obviously, that the HTTP{S} request we use must be recognizable, something COTS server software can be configured to respond to, in a way which will make the clients stop.

And so on and so forth...

In other words, we need a specification for how this should work.

As it happens ... my other software is the Varnish HTTP Accelerator and I do know a thing or two about HTTP and servers, so here is that specification.

Ideally, this should be run through an “Internet Draft” and pushed through a IETF WG and published as an RFC. If somebody wants to help with that, please drop me an email.

Here we go:

Introduction

This specification is for a stop-gap mechanism for synchronizing time across the network with authentication and integrity check.

Other protocols are in the pipeline, most notably NTS, which aim to do a better job than this mechanism can ever do, but it will take time before these protocols become widely available. This mechanism can provide a stop-gap service until then.

The editor encourages discussion and commentary on this mechanism takes place on this mailing list:

NTP Hackers <hackers@lists.ntp.org>

The official URL of this specification is:

http://phk.freebsd.dk/time/20151129.html

Outline

This mechanism is based on the fact that HTTP responses contain a “Date:” timestamp with second granularity, and that multiple requests can be sent serially on a single HTTP{S} connection.

By timing the queries sent, the client can attempt a binary search for when the “Date:” header changes on the server, and after a few iterations, the uncertainty can be brought down to a usable sub-second uncertainty, usable for many normal timekeeping needs.

This mechanism has significantly larger overhead, on the client and the server, and much larger jitter than NTP, so it is only meant as an infrequent “sanity-check” on regular NTP time synchronization.

HTTP{S} Request

The HTTP{S} requests sent by the client SHALL be exactly the following [2]

HEAD /.well-known/time HTTP/1.1\r\n
Host: <ip_or_fqdn>\r\n
User-Agent: <ident_string>\r\n
\r\n
\r\n

The url “/.well-known/time” is registered by IANA (See: RFC5785) (Thanks for the input Asbjørn!)

Where <ip_or_fqdn> is replaced by the identity of the server contacted. Please consult RFC7230 section 5.4 for more details.

The “<ident_string> should identify the client software, and preferably have the general form of “name/version”.

The client SHALL NOT add any other HTTP headers. This ban aims to minimize processing on the server, minimize information leaks, and to prevent poisoning logging records and statistics on the server.

The client SHALL NOT send any other HTTP requests on the same connection.

HTTP{S} Reponse

If the server does not consent to provide timing service to this client, it can reject the request with “Connection: close” in the first reponse [3].

The client SHALL cache the fact that the server refuses time service and SHALL NOT contact this server again.

If the server consents to provide timing service, it can respond with pretty much any valid HTTP response containing a “Date” header [4].

Client algorithm

The client algorithm is really simple:

t0 = now();
t2 = send_request_get_response_parse_date_header();
t1 = now();

The timestamp ‘t2’ names a particular second on the servers timescale.

It follows logically that second ‘t2’ at the very earliest can end shortly after ‘t0’, and it can start no later than just before ‘t1’.

The transition between second ‘t2’ and ‘t2+1’ must therefore happen sometime in the window [ ‘t0’ ... ‘t1 + 1 second’ ]

The client aims a second request/response transaction at the middle of this time-interval one second later, and provided the network cooperates, the new measurement will almost cut the window in half [5].

After three or four transactions, the client will generally have narrowed the window to a usable fraction of a second.

The client SHALL terminate after at most 8 transactions.

Because this mechanism delivers rather crude and noisy time mesurements, contemporary computer hardware will do just fine with one or two measurements per day.

Polling the server more often than that is just going to yank around the local clock needlessly, and in the case of holdover: Harmfully so.

The recommended usage of this mechanism is to acquire a trusted, sub-second time window when starting the computer, after which NTP should be used to steer the clock.

If hostile activity against the NTP traffic is suspected, the local clock should be allowed to coast (aka: “hold-over”), and this mechanism be used maybe twice a day to revalidate and gently steer the local clock relative to a trusted HTTPS server, while the NTP attack persists.

Once the hostilities cease, regular NTP synchronization can and should be resumed without a clock-step.

Improved timekeeping reponse

If the server wants to actively cooperate and improve client timekeeping, it can add an extra header to the responses, which provides a timestamp of higher resolution than the ‘Date’ header.

Adding this service generally reduces the time uncertainty window for the client to the round-trip-time making a single request/response sufficient in many cases, thus reducing the load on both the server and the clients.

The header to add for this is:

X-HTTPSTIME: <timestamp>

The <timestamp> SHALL be a decimal number using period (‘.’) as integer/fraction separator, and SHALL be at least one digit after the period [6] .

The number shall be a UNIX/POSIX ‘time_t’ number of seconds since 1970-01-01T00:00:00Z ignoring leap-seconds [7].

A trivial implementation could be [8]:

struct timeval tv;

assert(gettimeofday(&tv, NULL) == 0);
printf("X-HTTPSTIME: %ld.%06ld\r\n",
    (long)tv.tv_sec, (long)tv.tv_usec);

The client implementation is basically unchanged, it uses the “X-HTTPSTIME” timestamp instead of “Date”, and the initial window is sized [ ‘t0 ... ‘t1’ + granularity_of_timestamp ]

Security Considerations

The HTTPS (ie: SSL/TLS) handshake makes it possible for the client to authenticate the server, and the client must establish a policy and seed the necessary root-certificates for this.

Having identified the server with a certificate-chain does not vouch for the servers timekeeping, and this mechanism cannot communicate better time than the server has to begin with.

No explicit facility has been provided for the HTTP{S} server to communicate the (in)validity and (bad)health of its own timekeeping, but it can use the rejection methods outlined above to not disseminate bogus timestamps.

People have not put up HTTPS servers to deliver time. They may be willing to do so, but clients SHOULD NOT use HTTPS servers as time-sources without the express permission of the owner.

Needless to say, in-band attackers can attack HTTPS with packet-delay attacks, causing the measured time-window to be ureasonably large and/or fail to converge. The client algorithm will not fail to detect this.

Intellectual Property Considerations

The author asserts no intellectual property rights over this mechanism and is not aware of any other such claims.

Revision History

2015-12-12T10:00:00Z

Add User-Agent requirement. (input from Mark Nottingham)

2015-12-02T10:10:00Z

Changed url to be RFC5785 compliant and IANA registered. (input from Asbjørn Sloth Tønnesen)

2015-11-29T22:31:00Z

Initial revision.

phk

[1]“A parliament of” simply has to be the correct plural form of political issues, right ?
[2]A number of other possible requests have been tested against common HTTP{S} server software, and this one edged them all out. “OPTIONS” gave suboptimal timing results and simply didn’t work with some server software. “HEAD /” which by definition exists on all servers would not clearly stand out in NCSA format logfiles. Asking for a non-existent path, like “/HTPSTIME” will typically be, may give marginally better timing, but it was not statistically significant during tests against a random population of HTTPS servers.
[3]For extra emphasis, the server can delete the “Date:” header in the response, making timetransfer patently impossible.
[4]Timekeeping seems marginally better if the “/.well-known/time” url is left undefined on the HTTPS server, which causes an error response, (Typically “404 Not Found”). The improvement could be due to defeating HTTP-caches in the sampled server-population.
[5]“almost” covers the fact that the RTT prevents us from cutting it exactly in half.
[6]Little improvement in timekeeping results have been seen with resolution better than a millisecond (3 fractional digits).
[7]Ideally separate receive and transmit timestamps should be communicated, as in the NTP and PTP protocols. The timekeeping advantage of that would be significantly eroded by the encryption overhead and since implementing it in current HTTP{S} server software would be non-trivial only one timestamp is used.
[8]Non se habla PHP