RFC 10049
Roughtime: A Protocol for Rough Time Synchronization
Roughtime: A Protocol for Rough Time Synchronization ๐ฐ๏ธโจ
Okay bestie, here's the paperwork tea before we dive in ๐
- RFC: 10049 ๐
- Series: Internet Engineering Task Force (IETF) ๐
- Authors: W. Ladd (Akamai Technologies) and M. Dansarie (Netnod) ๐
- Category: Experimental ๐งช
- ISSN: 2070-1721
- Date: October 2026 ๐ธ
- Obsoletes / Updates: nothing listed in this title block, so it doesn't obsolete or update anything ๐ซถ
Abstract ๐ฆ
Roughtime is an experimental protocol with two big jobs ๐ The first is secure, rough time synchronization, even for clients that have no clue what time it is. The second is a format that lets clients report any inconsistencies they spot between timeservers. This doc specifies the on-wire protocol needed for all of that, and it also talks through the ecosystem pieces it needs to actually work โจ
Status of This Memo ๐
Okay so this document is not an Internet Standards Track specification ๐ It's published for examination, experimental implementation, and evaluation.
This document defines an Experimental Protocol for the Internet community. It's a product of the Internet Engineering Task Force (IETF) and represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). Not every document the IESG approves is a candidate for any level of Internet Standard, so see Section 2 of RFC 7841 for the details ๐
Info about the current status of this document, any errata, and how to give feedback is at https://www.rfc-editor.org/info/rfc10049 ๐
Copyright Notice ยฉ
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved ๐
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they're in effect on the date of publication. Please read these carefully, because they spell out your rights and restrictions for this document ๐ Code Components pulled out of this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as described in the Revised BSD License โญ
Table of Contents ๐บ๏ธ
1. Introduction
2. Conventions
3. Protocol Overview
3.1. Single Server Mode
3.2. Multi-server Mode
4. Message Format
4.1. Data Types
4.1.1. uint32
4.1.2. uint64
4.1.3. Tag
4.1.4. Timestamp
4.2. Header
5. Protocol Details
5.1. Requests
5.1.1. VER
5.1.2. NONC
5.1.3. TYPE
5.1.4. SRV
5.1.5. ZZZZ
5.2. Responses
5.2.1. SIG
5.2.2. NONC
5.2.3. TYPE
5.2.4. PATH
5.2.5. SREP
5.2.6. CERT
5.2.7. INDX
5.3. The Merkle Tree
5.3.1. Root Value Validity Check Algorithm
5.4. Validity of Response
6. Integration into NTP
7. Grease
8. Roughtime Clients
8.1. Necessary Configuration
8.2. Measurement Sequence
8.3. Server Lists
8.4. Malfeasance Reporting
8.4.1. Malfeasance Report Format
8.4.2. Reporting
9. Security Considerations
9.1. Confidentiality
9.2. Integrity and Authenticity
9.3. Generating Private Keys
9.4. Private Key Compromise
9.5. Quantum Resistance
9.6. Maintaining Lists of Servers
9.7. Amplification Attacks
10. Privacy Considerations
11. Operational Considerations
12. IANA Considerations
12.1. Service Name and Transport Protocol Port Number Registry
12.2. Roughtime Versions Registry
12.3. Roughtime Tags Registry
12.4. Media Type Registry
12.4.1. Media Type for Roughtime Server List
12.4.2. Media Type for Roughtime Malfeasance
13. References
13.1. Normative References
13.2. Informative References
Appendix A. Example Server List
Appendix B. Example Malfeasance Report
Acknowledgments
Authors' Addresses
1. Introduction โจ
Time sync is essential to Internet security because so many security protocols and other apps need it [RFC0738] ๐ The catch is that widely deployed protocols like the Network Time Protocol (NTP) [RFC5905] lack essential security features, and even newer ones like Network Time Security (NTS) [RFC8915] have no way to observe whether the servers are behaving correctly ๐ Clients might not even have a basic idea of the time either, which causes bootstrapping problems, since time is needed for X.509 certificate validation ๐
The main design goal of Roughtime is to let devices get a rough idea of the current time from a fairly static configuration, and to let them report any inconsistencies they see between servers ๐ That configuration is a list of servers and their associated long-term keys, which ideally stay unchanged for a server's whole lifetime. So the long-term public keys are the roots of trust in Roughtime ๐ณ With a long enough list of trusted servers and keys, a client can acquire authenticated time with high probability, even after long stretches of inactivity ๐ค Proofs of malfeasance, built by chaining together responses from different trusted servers, can prove a server misbehaved and, after analysis, can lead to revoking trust in that particular key โ๏ธ
Unlike Khronos [RFC9523], Roughtime produces external evidence that time servers are reporting incompatible times ๐ฅ That means the timestamp format has to change, so it can't just be a mere extension to NTP ๐ โโ๏ธ
Real operational experience is needed to figure out whether Roughtime is viable for secure time bootstrapping in Internet-connected systems ๐งช That includes running a Roughtime ecosystem with services that maintain and distribute lists of trusted servers and process malfeasance reports. To make those experiments happen, this document only covers the Roughtime on-wire protocol ๐ก Apart from describing the server list and malfeasance report formats, it doesn't describe the ecosystem, the way the server list is maintained and distributed, or the policies to apply to such a list ๐ซถ
2. Conventions ๐งท
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be read as described in BCP 14 [RFC2119] [RFC8174], but only when they appear in all capitals, just like shown here ๐ Lowercase versions are just regular words, no special powers ๐
3. Protocol Overview ๐ธ
Roughtime is a protocol for authenticated, rough time synchronization that lets clients get cryptographic proof of server malfeasance ๐ต๏ธโโ๏ธ The way it works is that server responses include a signature over a value derived from the client's request, and that request includes a nonce. That gives cryptographic proof that the response was issued after the server got the client's request ๐งพ The derived value in the response is the root of a Merkle tree [Merkle] that includes the hash of the client's request as the value of one of its leaf nodes. The tree lets the server amortize the relatively costly signing operation across a bunch of client requests ๐ณโจ
3.1. Single Server Mode ๐งโโ๏ธ
At its most basic, Roughtime is a one-round protocol. A totally fresh client asks for the current time, and the server sends back a signed response ๐จ The response includes a timestamp and a radius, which shows how certain the server is about the reported time ๐ฏ
The client's request contains a nonce that the server folds into its signed response. The client can verify the server's signatures, and as long as the nonce has sufficient entropy, that proves the signed response could only have been generated after the nonce existed ๐
3.2. Multi-server Mode ๐ฏโโ๏ธ
When you use multiple servers, a client can detect, cryptographically prove, and report inconsistencies between them ๐จ
A Roughtime server guarantees that the timestamp in its response is generated after it receives the request and before it transmits the matching response โฑ๏ธ If a server's time response doesn't match the responses from other servers, that points to server error or intentional malfeasance. It can be reported and potentially used to impeach the server โ๏ธ
Proofs of malfeasance are built by chaining requests across different Roughtime servers. Details on proofs and malfeasance reporting are in Section 8 ๐ For reporting to actually result in impeachment, an additional mechanism is required that provides a review and impeachment process. Defining that mechanism is beyond the scope of this document. One simple option could be an online forum where a court of human observers evaluates cases after reviewing the input reports ๐งโโ๏ธ๐
4. Message Format ๐
Roughtime messages are maps made of one or more (tag, value) pairs ๐๏ธ They start with a header that holds the number of pairs, the value offsets, and the tags. The header is followed by a message values section, which holds the values tied to the tags in the header. Messages are formatted according to Figure 1, as described in the subsections below ๐งฉ
In some cases messages are recursive, meaning the value of a tag can itself be a Roughtime message ๐ช
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Number of pairs, N (uint32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
. .
. N-1 offsets (uint32) .
. .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
. .
. N tags (uint32) .
. .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
. .
. N values .
. .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 1: Roughtime Message
4.1. Data Types ๐ง
4.1.1. uint32 ๐ข
A uint32 is a 32-bit unsigned integer. It's serialized with the least significant byte first ๐พ
4.1.2. uint64 ๐ข
A uint64 is a 64-bit unsigned integer. It's serialized with the least significant byte first too ๐
4.1.3. Tag ๐
okay bestie, tags are the little labels ๐ท๏ธ we stick on each value inside a Roughtime message so the receiver knows what's what. A tag is exactly four octets. Each one starts with one to four capital ASCII letters (A-Z) [RFC0020], followed by zero to three padding zero octets. Throughout this doc we talk about tags by their ASCII string, but under the hood they get registered and sorted as uint32 values, where the least significant byte is the first octet in the sequence. ngl it's a lot, but it's giving precision ๐
For example, the ASCII string "NONC" corresponds to the uint32 0x434e4f4e, which gets serialized as {0x4e, 0x4f, 0x4e, 0x43}. "VER" corresponds to 0x00524556 and gets serialized as {0x56, 0x45, 0x52, 0x00}. the byte order is giving reverse-engineering vibes ๐ง
4.1.4. Timestamp ๐ฐ๏ธ
a timestamp is UTC time written as a uint64 count of seconds since 00:00:00 on 1 January 1970 (the Unix epoch), assuming every day has 86400 seconds. it's a constant offset from the NTP timestamp in seconds. the tricky part is that leap seconds don't have an unambiguous representation in a timestamp, and that has implications for the attainable accuracy and for how the RADI tag gets set (see Section 5.2.5). this is the kind of detail that keeps me up at night ๐ญ
4.2. Header ๐ฆ
as shown in Figure 1, the first four bytes of the header are the uint32 number of tags N, and that tells you how many (tag, value) pairs you're dealing with. the next 4*(N-1) bytes are offsets, each a uint32, and the last 4*N bytes in the header are tags.
the offsets array is considered to have an implicitly encoded value of 0 as its zeroth entry. its members point to the positions of the tag values in the message values section. all offsets are multiples of four ๐ข
the members of the offsets and tags arrays, plus the message values section, are sorted in ascending order by the tag's uint32 value. so the offset array is also sorted in ascending order, which is so clean ๐ซถ A tag MUST NOT appear more than once in a header.
the first post-header byte (aka the first byte of the message values section) is at offset 0. the value for the ith tag begins at offset[i] and ends at offset[i+1]-1, except for the last value, which ends at the end of the message. Values MAY have zero length. all lengths and offsets are in bytes ๐ธ
5. Protocol Details ๐
as we covered in Section 3, clients kick off time sync by sending requests with a nonce, and servers send back signed time responses. Roughtime packets can travel between clients and servers either as UDP datagrams or over TCP streams. Servers SHOULD support both the UDP and TCP transport modes ๐
Roughtime packets are formatted like Figure 2 and as described here. the first field is a uint64 with the value 0x4d49544847554f52 ("ROUGHTIM" in ASCII). the second field is a uint32 that holds the length of the third field. the third and last field is a Roughtime message as specified in Section 4.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x4d49544847554f52 (uint64) |
| ("ROUGHTIM") |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message length (uint32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
. .
. Roughtime message .
. .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 2: Roughtime Packet
Roughtime request and response packets MUST be transmitted in a single datagram when the UDP transport mode is used. Setting the packet's Don't Fragment bit [RFC0791] is OPTIONAL in IPv4 networks. Setting it may cause packets to get dropped, but not setting it could lead to long delays due to reconstruction and dropped fragments ๐
a Roughtime packet could exceed the maximum deliverable length of a packet on a particular path, which would make Roughtime queries over UDP impossible on that path. so if a client isn't getting responses to its UDP queries, it SHOULD attempt to use the TCP transport mode for Roughtime queries to that server ๐ฆ
Clients MUST implement exponential backoff in establishing TCP connections and making requests over UDP. It is RECOMMENDED that clients use an initial retry interval of 1 second, a maximum interval of 24 hours, and a base of 1.5. So the minimum interval, in seconds, before retrying after n failures is min(1.5^(n-1), 86400). If you're an implementer thinking about other values, Section 3.1.3 of [RFC8085] has guidance for you โจ
Clients MUST NOT reset the retry interval until they receive a properly signed response. no shortcuts, bestie ๐ โโ๏ธ
Multiple requests and responses can be exchanged over an established TCP connection. Clients MAY send multiple outstanding requests and servers MAY send responses out of order. The connection SHOULD be closed by the client when it has no more requests to send and has received all expected responses. Either side SHOULD close the connection in response to synchronization, format, implementation-defined timeouts, or other errors ๐
All requests and responses contain the VER tag. It holds a list of one or more uint32 version numbers. The version of Roughtime specified by this document has version number 1 ๐
5.1. Requests ๐
a request contains the tags VER, NONC, and TYPE. It SHOULD include the tag SRV. Unknown tags MUST be ignored by the server. Requests that don't contain the three mandatory tags MUST be ignored. A future version of this protocol may mandate additional tags in the message and assign them semantic meaning ๐
the size of the request message SHOULD be at least 1024 bytes when the UDP transport mode is used. to hit that size, the ZZZZ tag gets added to the message. one reason you might send smaller requests is to use the UDP transport mode over paths with a low maximum deliverable length. responding to request messages shorter than 1024 bytes is OPTIONAL, but servers MUST NOT send responses larger than the request messages they're replying to; see Section 9.7. size matters, and this is the rule ๐
5.1.1. VER ๐ท
in a request, the VER tag holds a list of uint32 version numbers. The VER tag MUST include at least one Roughtime version supported by the client, and it MUST NOT contain more than 32 version numbers. The version numbers and tags included in the request MUST be compatible with each other and with the packet contents.
The version numbers MUST NOT repeat and MUST be sorted in ascending numerical order.
Servers MUST ignore any unknown version numbers in the list supplied by the client. If the list contains no version numbers the server supports, it MAY respond with another version or ignore the request entirely; see Section 5.2.5. ๐ซ
5.1.2. NONC ๐ฒ
the value of the NONC tag is a 32-byte nonce. It SHOULD be generated in a manner indistinguishable from random. RFC 4086 [BCP106] has specific guidelines on this. Section 8.2 explains how to securely generate nonces when querying multiple servers in sequence ๐
5.1.3. TYPE ๐ท๏ธ
the TYPE tag is how you unambiguously tell request and response messages apart. In a request, it MUST contain a uint32 with value 0. Requests with a TYPE tag holding any other value MUST be ignored by servers.
5.1.4. SRV ๐
the SRV tag tells the server which long-term public key the client expects to verify the response with. The value of the SRV tag is H(0xff || public_key), where public_key is the server's long-term, 32-byte Ed25519 public key, and H is SHA-512 truncated to the first 32 bytes. it's giving key-identity energy ๐
5.1.5. ZZZZ ๐ซง
the ZZZZ tag exists to pad the request out to the minimum required length. Its value is all zero bytes.
5.2. Responses ๐
the server starts handling the request with a set of long-term keys. It figures out which long-term key to use with the following procedure:
- If the request contains a
SRVtag, then the server looks up the long-term key indicated by theSRVvalue. If no such key exists, then the server MUST ignore the request. - If the request contains no
SRVtag, but the server has just one long-term key, it SHOULD select that key. Otherwise, if the server has multiple long-term keys, then it MUST ignore the request.
a response contains the tags SIG, NONC, TYPE, PATH, SREP, CERT, and INDX. Figure 3 shows what a response message looks like ๐งฉ
|--SIG
|--NONC
|--TYPE
|--PATH
|--SREP
| |--VER
| |--RADI
| |--MIDP
| |--VERS
| |--ROOT
|--CERT
| |--SIG
| |--DELE
| | |--PUBK
| | |--MINT
| | |--MAXT
|--INDX
Figure 3: Roughtime Response Message Structure
No mechanism exists for reporting errors (like a wrong request format, an unsupported version, or an unknown SRV value) back to the client. This comes from experience with the NTP protocol, where Kiss-o'-Death packets (see Section 7.4 of [RFC5905]) are used to indicate errors. The existence of this unauthenticated protocol feature in NTP makes it possible for on-path attackers to make a client stop using authenticated modes or certain servers altogether (see Section 5.4 of [RFC8633] and Sections 8.3 and 8.7 of [RFC8915]). Since the protocol depends on multiple independent servers for security, error reporting functionality has been excluded from this version of Roughtime.
๐จ on-path attackers can literally make a client give up on authenticated modes or on certain servers if error reports are unauthenticated. that's exactly why Roughtime skips error reporting altogether. protect your clients, bestie ๐ก๏ธ
5.2.1. SIG โ๏ธ
in general, a SIG tag value is a 64-byte Ed25519 signature [RFC8032] over a concatenation of a context string and the entire value of a tag. All context strings include a terminating zero byte.
the SIG tag in the root of a response is a signature over the SREP value, made with the public key in CERT, using the context string "Roughtime v1 response signature" ๐
5.2.2. NONC ๐
the NONC tag contains the nonce of the message being responded to.
5.2.3. TYPE ๐ธ
In a response, the TYPE tag MUST contain a uint32 with value 1. Responses with a TYPE tag holding any other value MUST be ignored by clients.
5.2.4. PATH ๐ช
the PATH tag value is a multiple of 32 bytes long and represents a path of 32-byte hash values in the Merkle tree used to generate the ROOT value, as described in Section 5.3. If a response is prepared for a single request and the Merkle tree only contains the root node, then the size of PATH is zero ๐ณ
The PATH MUST NOT contain more than 32 hash values. The maximum length of PATH is normally limited by the maximum size of the response message; see Sections 5.1 and 9.7. Server implementations MUST select a maximum Merkle tree height (see Section 5.3) that ensures this. tree height, but make it responsible ๐ฅ
5.2.5. SREP ๐
okay so the SREP tag is where the signed response actually lives ๐ its value is a Roughtime message with the tags VER, RADI, MIDP, VERS, and ROOT, so it's basically a mini packet tucked inside the packet, iykyk ๐ช
The VER tag, when it shows up in a response, holds a single uint32 version number. It SHOULD be one of the version numbers the client sent in its request (see Section 5.1.1) ๐ซถ and the server MUST ensure that the version number lines up with the rest of the packet contents. no mismatches allowed bestie ๐
The RADI tag value is a uint32 representing the server's estimate of how accurate MIDP is, in seconds ๐ Servers MUST ensure that the true time is within (MIDP-RADI, MIDP+RADI) at the moment of processing. The value of RADI MUST NOT be zero, ngl that would be giving false confidence ๐ Since leap seconds can't be unambiguously represented by Roughtime timestamps, servers MUST take this into account when setting the RADI value during leap second events ๐ Servers that do not have any leap second information SHOULD set the value of RADI to at least 3. Failure to do so will impact the observed correctness of Roughtime servers and can lead to malfeasance reports, and nobody wants that era ๐ญ
The MIDP tag value is the timestamp of the moment of processing โฐ
The VERS tag value contains a list of uint32 version numbers supported by the server, sorted in ascending numerical order ๐ It MUST contain the version number specified in the VER tag. It MUST NOT contain more than 32 version numbers.
The ROOT tag contains a 32-byte value of a Merkle tree root, as described in Section 5.3 ๐ณ
5.2.6. CERT ๐
The CERT tag contains a public key certificate signed with the server's private long-term key. Its value is a Roughtime message with the tags SIG and DELE, where SIG is a signature over the DELE value with the context string "Roughtime v1 delegation signature" โ๏ธ
The DELE tag contains a delegated public key certificate used by the server to sign the SREP tag. Its value is a Roughtime message with the tags PUBK, MINT, and MAXT. The whole point of DELE is to separate a long-term public key from keys on devices exposed to the public Internet, which is such a smart move ๐ง โจ
The PUBK tag contains a temporary 32-byte Ed25519 public key that is used to sign the SREP tag ๐
The MINT tag is the minimum timestamp for which the key in PUBK is trusted to sign responses. MIDP MUST be more than or equal to MINT for a response to be considered valid โ
The MAXT tag is the maximum timestamp for which the key in PUBK is trusted to sign responses. MIDP MUST be less than or equal to MAXT for a response to be considered valid ๐
5.2.7. INDX ๐
The INDX tag value is a uint32 determining the position of NONC in the Merkle tree used to generate the ROOT value, as described in Section 5.3 ๐บ๏ธ
5.3. The Merkle Tree ๐ฒ
A Merkle tree [Merkle] is a binary tree where the value of each non-leaf node is a hash value derived from its two children. The root of the tree is thus dependent on all leaf nodes ๐
In Roughtime, each leaf node in the Merkle tree represents one request. Leaf nodes are indexed left to right, beginning with zero ๐๐
The values of all nodes are calculated from the leaf nodes and up towards the root node using the first 32 bytes of the output of the SHA-512 hash algorithm [RFC6234]. For leaf nodes, the byte 0x00 is prepended to the full value of the client's request packet, including the "ROUGHTIM" header, before applying the hash function. For all other nodes, the byte 0x01 is concatenated with first the left and then the right child node value before applying the hash function ๐งฎ
The value of the Merkle tree's root node is included in the ROOT tag of the response.
The index of a request leaf node is included in the INDX tag of the response.
The values of all sibling nodes in the path between a request leaf node and the root node are stored in the PATH tag, so that the client can reconstruct and validate the value in the ROOT tag using its request packet. These values are each 32 bytes and are stored one after the other with no additional padding or structure. The order in which they are stored is described in the following subsection ๐ฆ
5.3.1. Root Value Validity Check Algorithm ๐งฉ
This section describes how to compute the value of the root of the Merkle tree from the values in the tags PATH, INDX, and NONC. The bits of INDX are ordered from least to most significant. H(x) denotes the first 32 bytes of the SHA-512 hash digest of x, and || denotes concatenation.
The algorithm maintains a current value h. At initialization, h is set to H(0x00 || request_packet). For each step of the algorithm, let node be the next 32 bytes in PATH. If the current bit in INDX is 0 then h = H(0x01 || h || node), else h = H(0x01 || node || h). When no more entries remain in PATH, h is compared to the value of the root of the Merkle tree contained in ROOT. If they are equal, the algorithm succeeds. If they are not, or if any of the remaining bits of INDX is non-zero, the algorithm fails ๐ฏ
5.4. Validity of Response โ
A client MUST check the following properties when it receives a response. We assume the long-term server public key is known to the client through other means ๐
The signature in CERT was made with the long-term key of the server.
The MIDP timestamp lies in the interval specified by the MINT and MAXT timestamps.
The INDX and PATH values prove a hash value derived from the request packet was included in the Merkle tree with value ROOT using the algorithm in Section 5.3.1.
The signature of SREP in SIG validates with the public key in DELE.
A response that passes these checks is said to be valid. Validity of a response does not prove that the timestamp's value in the response is correct, but merely that the server guarantees that it signed the timestamp and computed its signature during the time interval (MIDP-RADI, MIDP+RADI) ๐ฐ๏ธ
6. Integration into NTP ๐
We assume that there is a bound phi on the frequency error in the clock on the machine. Let delta be the time difference between the clock on the client and the clock on the server, and let sigma represent the error in the measured value of delta introduced by the measurement process. Given a measurement taken at a local time t, we know the true time is in (t-delta-sigma, t-delta+sigma). After d seconds have elapsed we know the true time is within (t-delta-sigma-d*phi, t-delta+sigma+d*phi) ๐ง
This bound can be used as a simple and effective means to limit the error an attacker can introduce into NTP or Precision Time Protocol (PTP) measurements. For example, an NTP client can ensure that its observation intervals fall entirely within this range, or can reject measurements that fall outside ๐ก๏ธ
An application that needs to verify X.509 certificates (which requires knowledge of the current time) but lacks an accurate and trusted time source can use Roughtime to obtain a time estimate. In particular, securely establishing NTS-protected NTP time synchronization requires verification of the NTS-KE server's certificate, which is not possible if the client has no idea of the current time (see Section 8.5 of [RFC8915]). In that case, a Roughtime time estimate can be used for certificate validation ๐
If an NTP server uses a Roughtime server as a time source for synchronization (and not only for filtering its NTP measurements), the root dispersion SHOULD include the server's RADI value, and root delay SHOULD include the interval between sending the Roughtime request and receiving the response ๐ค
7. Grease ๐งด
The primary purpose of grease is to prevent protocol ossification, which could prohibit future protocol extensions and development [RFC9170]. In Roughtime, grease is also intended to ensure that clients validate signatures. To grease the Roughtime protocol, servers SHOULD send back a fraction of responses with any of the following: lack of mandatory tags, version numbers not in the request, undefined tags, or invalid signatures together with incorrect times. Clients MUST properly ignore undefined tags and reject invalid responses. Servers MUST NOT send back responses with incorrect times and valid signatures. Either signature in the response (i.e., of the SREP or DELE tag) MAY be invalid for this application ๐ซง
Warning: servers must never send back responses with incorrect times and valid signatures. Grease is only for the cases listed above ๐จ
Hmm, that last aside isn't a requirement; delete. Final answer continues below without it.
8. Roughtime Clients ๐ฑ
8.1. Necessary Configuration โ๏ธ
To carry out a Roughtime measurement, a client needs a list of servers, a minimum of three of which are operational and not run by the same parties. Roughtime clients SHOULD regularly update their view of which servers are trustworthy in order to benefit from the detection of misbehavior (see Section 8.3). Clients SHOULD also have a means of reporting to the provider of such a list, such as an operating system or software vendor, a malfeasance report as described in Section 8.4 ๐
8.2. Measurement Sequence ๐
The client randomly selects at least three servers from the list, and sequentially queries them. To ensure that all possible inconsistencies can be detected, it is necessary for clients to repeat the query sequence twice with the servers in the same order.
The first probe uses a nonce that is randomly generated. The second query uses H(resp || rand) where rand is a random 32-byte value and resp is the entire response to the first probe, including the "ROUGHTIM" header. Each subsequent query uses H(resp || rand) for the previous response and a different 32-byte rand value. H(x) and || are defined as in Section 5.3.1.
For each pair of responses (i, j), where i was received before j, the client MUST check that MIDP_i-RADI_i is less than or equal to MIDP_j+RADI_j. If these checks pass, the times are consistent with causal ordering. The measurement succeeds if the validity checks described in Section 5.4 are successful, the times reported are consistent with causal ordering, and the delay between request and response is within an implementation-dependent maximum value ๐
If the validity checks are successful, but at least one of the responses is not consistent with causal ordering, there has been a malfeasance. In case of detected malfeasance, clients SHOULD, if it is technically possible, generate a malfeasance report (see Section 8.4), alert the user, and make another measurement. See Section 5 for guidance on backoff when making repeated measurements ๐จ
8.3. Server Lists ๐โจ
Okay so, to keep your list of trusted servers fresh, there's a shared server list format defined right here ๐ซถ. Supporting this common format is OPTIONAL ๐ , and clients MAY instead build their own way of configuring server lists ๐ ๏ธ.
A server list is a JSON object [RFC8259] that has the key servers ๐. Server list objects MAY also have the keys sources and reports ๐ธ. Appendix A has an example server list in this format ๐.
Server lists get the application/roughtime-server+json media type ๐ง.
The value of servers is a list of server objects, and each one has the keys name, version, publicKeyType, publicKey, and addresses ๐.
The value of name is a string with a server name that's readable for a human ๐.
The value of version is an integer for the highest Roughtime version number the server supports ๐ฅ.
The value of publicKeyType is a string naming the signature scheme the server uses. For servers that support version 1 of Roughtime, it's ed25519 ๐.
The value of publicKey is a base64-encoded [RFC4648] string holding the server's long-term public key, in a format that matches publicKeyType ๐.
The value of addresses is a list of address objects. Each address object has the keys protocol and address ๐ฆ. The value of protocol is either tcp or udp, which tells you the transport mode to use ๐. The value of address is a string with a host and a port number separated by a colon, like roughtime.example.com:5319 โจ. The host part is an IPv4 address, an IPv6 address, or a fully qualified domain name (FQDN) ๐. IPv4 addresses are written in dotted decimal notation. IPv6 addresses MUST conform to the "Text Representation of Addresses" (Section 2.2 of [RFC4291]) and MUST NOT include zone identifiers [RFC9844] ๐. To tell an IPv6 address apart from the port when zero compression happens, the IPv6 address gets wrapped in [] ๐งฉ. The port part is a decimal integer for a valid port number, so anything in the range 0-65535 ๐.
The value of sources, if it's there, is a list of strings that say where updated versions of the list can be grabbed using the HTTP GET method [RFC9110] ๐ฅ. Each string is a URL [RFC3986] pointing to a list in the format specified here ๐. The URI scheme MUST be HTTPS [RFC9110] ๐.
The value of reports, if it's there, is a string with a URL [RFC3986] where clients can send malfeasance reports using the HTTP POST method ๐ฎ. The URI scheme MUST be HTTPS [RFC9110] ๐.
8.4. Malfeasance Reporting ๐ต๏ธโโ๏ธ
A malfeasance report is cryptographic proof that a sequence of responses arrived in that order. It can be used to demonstrate that at least one server sent the wrong time โฐ๐จ. Iconic evidence energy, no cap ๐ .
8.4.1. Malfeasance Report Format ๐
A malfeasance report is a JSON object [RFC8259] with the key responses ๐. Its value is a list of response objects, sorted in the order they were received ๐. Each response object has the keys rand, publicKey, request, and response. All four values are represented as base64-encoded [RFC4648] strings ๐ซง. Appendix B has an example malfeasance report in this format ๐ธ.
Malfeasance reports have the application/roughtime-malfeasance+json media type ๐งโโ๏ธ.
The rand key MAY be left out of the first response object in the list ๐. In every other case, its value is the 32-byte value that was used to generate the request nonce value from the previous response packet ๐ข.
The value of publicKey is the long-term key the server was expected to use for deriving the response signature ๐.
The value of request is the transmitted request packet, including the ROUGHTIM header ๐ค.
The value of response is the received response packet, including the ROUGHTIM header ๐ฅ.
8.4.2. Reporting ๐ฃ
When the client's list of servers has an associated URL for malfeasance reports, it SHOULD send a malfeasance report to that URL when malfeasance is detected (see Section 8.2) and it's technically feasible to do so ๐. Malfeasance reports are sent using the HTTP POST method [RFC9110] ๐ฎ.
Okay, this part is so important ๐ญ. Since the failure of a popular Roughtime server can make a ton of clients send malfeasance reports at the exact same time, clients MUST use exponential backoff so they don't overload the server receiving the reports ๐ซ . It is RECOMMENDED that clients use an initial retry interval of 10 seconds, a maximum interval of 24 hours, and a base of 1.5 ๐. So the minimum interval, in seconds, before retrying after n failures is min(10 * 1.5^(n-1), 86400) ๐งฎโจ.
Clients MUST NOT send malfeasance reports in response to signature verification failures or any other protocol errors. Not me being dramatic, but this one is a hard no ๐ซ๐.
As described in Section 1, the operational rules for accepting or rejecting a particular malfeasance report are beyond the scope of this document ๐ค.
9. Security Considerations ๐
9.1. Confidentiality ๐คซ
This protocol does not provide any confidentiality. Given the nature of timestamps, such impact is minor ๐ฐ๏ธ.
9.2. Integrity and Authenticity ๐ก๏ธ
The Roughtime protocol only provides integrity and authenticity protection for data contained in the SREP tag. Accordingly, new tags SHOULD be added to the SREP tag whenever possible ๐.
9.3. Generating Private Keys ๐๏ธ
Although any random 256-bit string can be used as a private Ed25519 key, it has a high risk of being vulnerable to small-subgroup attacks and timing side-channel leaks ๐ฑ. For this reason, all private keys used in Roughtime MUST be generated following the procedure described in Section 5.1.5 of [RFC8032] ๐๐ฅ.
9.4. Private Key Compromise ๐
The compromise of a PUBK's private key, even past MAXT, is a problem ๐จ. The private key can be used to sign invalid times that are in the range MINT to MAXT, which violates the good-behavior guarantee of the server ๐ญ. To protect against this, it is necessary for clients to query multiple servers in accordance with the procedure described in Section 8.2 ๐ก๏ธโจ.
9.5. Quantum Resistance ๐
Since the only supported signature scheme, Ed25519, is not quantum resistant, the Roughtime version described in this document will not survive the advent of quantum computers ๐ซฃ. A later version will have to be devised and implemented before then โณ. Using a single version number as the negotiation point, instead of defining a suite of acceptable signatures, is intended to prevent fragmentation and misconfiguration ๐งฉ.
9.6. Maintaining Lists of Servers ๐
The infrastructure and procedures for maintaining a list of trusted servers, and for adjudicating violations of the rules by servers, are not discussed in this document. They are essential for security ๐ซถ.
9.7. Amplification Attacks ๐ข
UDP protocols that send responses significantly larger than their requests, such as NTP, have previously been leveraged for amplification attacks ๐ค. To prevent Roughtime from being used for such attacks, servers MUST NOT send response packets larger than the request packets sent by clients. ๐ซ๐ฅ
10. Privacy Considerations ๐ซง
This protocol is designed to obscure all client identifiers ๐. Servers necessarily have persistent long-term identities, which are essential to enforcing correct behavior ๐ชช. Generating nonces in a nonrandom manner can cause leaks of private data or enable tracking of clients as they move between networks ๐.
11. Operational Considerations โ๏ธ
It is expected that clients identify a server by its long-term public key ๐. In multi-tenancy environments, where multiple servers may be listening on the same IP or port space, the protocol is designed so that the client indicates which server it expects to respond ๐ . This is done with the SRV tag ๐ท๏ธ. Additional recommendations for clients are listed in Section 8 ๐.
12. IANA Considerations ๐๏ธ
12.1. Service Name and Transport Protocol Port Number Registry ๐
IANA has allocated the following entry in the "Service Name and Transport Protocol Port Number Registry":
Service Name: roughtime
Transport Protocol: tcp, udp
Assignee: IESG <iesg@ietf.org>
Contact: IETF Chair <chair@ietf.org>
Description: Roughtime time synchronization
Reference: RFC 10049
Port Number: 5319
12.2. Roughtime Versions Registry ๐ท๏ธ
IANA has created a new registry titled "Roughtime Versions" in a new "Roughtime" registry group. Entries have the following fields:
Version ID(REQUIRED): A 32-bit unsigned integerVersion Name(REQUIRED): A short text string naming the version being identifiedReference(REQUIRED): A reference to a relevant specification document
The policy for allocation of new entries is IETF Review [RFC8126] ๐.
The initial contents of this registry are specified below ๐.
+=======================+===============================+===========+
| Version ID | Version Name | Reference |
+=======================+===============================+===========+
| 0x0 | Reserved | RFC 10049 |
+-----------------------+-------------------------------+-----------+
| 0x1 | Roughtime version 1 | RFC 10049 |
+-----------------------+-------------------------------+-----------+
| 0x2-0x7fffffff | Unassigned | |
+-----------------------+-------------------------------+-----------+
| 0x80000000-0xbfffffff | Reserved for | RFC 10049 |
| | Experimental Use | |
+-----------------------+-------------------------------+-----------+
| 0xc0000000-0xffffffff | Reserved for | RFC 10049 |
| | Private Use | |
+-----------------------+-------------------------------+-----------+
Table 1: Initial Contents of the Roughtime Versions Registry
Private and Experimental Use are defined in [RFC8126] ๐งโ๐ป. The experimental range is intended for testing and evaluating new versions of the Roughtime protocol ๐งช. Such tests may be conducted over the open Internet ๐โจ.
12.3. Roughtime Tags Registry โจ
okay so IANA made a brand new registry called "Roughtime Tags" ๐, and it lives in its own shiny new "Roughtime" registry group ๐ . every entry has three fields, and they're all REQUIRED (no skipping, bestie) ๐ซถ:
Tag(REQUIRED): a 32-bit unsigned integer written in hexadecimal format ๐ขASCII Representation(REQUIRED): the ASCII representation of the tag, done in accordance with Section 4.1.3 of this document โ๏ธReference(REQUIRED): a reference to a relevant specification document ๐
the allocation policy for new entries is Specification Required [RFC8126], so it's giving strict-but-fair energy ๐
and the starting lineup? it's all in Table 2 ๐, and every single one of them points back to RFC 10049 ๐ฆ
+============+======================+===========+
| Tag | ASCII Representation | Reference |
+============+======================+===========+
| 0x00474953 | SIG | RFC 10049 |
+------------+----------------------+-----------+
| 0x00524556 | VER | RFC 10049 |
+------------+----------------------+-----------+
| 0x00565253 | SRV | RFC 10049 |
+------------+----------------------+-----------+
| 0x434e4f4e | NONC | RFC 10049 |
+------------+----------------------+-----------+
| 0x454c4544 | DELE | RFC 10049 |
+------------+----------------------+-----------+
| 0x45505954 | TYPE | RFC 10049 |
+------------+----------------------+-----------+
| 0x48544150 | PATH | RFC 10049 |
+------------+----------------------+-----------+
| 0x49444152 | RADI | RFC 10049 |
+------------+----------------------+-----------+
| 0x4b425550 | PUBK | RFC 10049 |
+------------+----------------------+-----------+
| 0x5044494d | MIDP | RFC 10049 |
+------------+----------------------+-----------+
| 0x50455253 | SREP | RFC 10049 |
+------------+----------------------+-----------+
| 0x53524556 | VERS | RFC 10049 |
+------------+----------------------+-----------+
| 0x544e494d | MINT | RFC 10049 |
+------------+----------------------+-----------+
| 0x544f4f52 | ROOT | RFC 10049 |
+------------+----------------------+-----------+
| 0x54524543 | CERT | RFC 10049 |
+------------+----------------------+-----------+
| 0x5458414d | MAXT | RFC 10049 |
+------------+----------------------+-----------+
| 0x58444e49 | INDX | RFC 10049 |
+------------+----------------------+-----------+
| 0x5a5a5a5a | ZZZZ | RFC 10049 |
+------------+----------------------+-----------+
Table 2: Initial Contents of the Roughtime
Tags Registry
12.4. Media Type Registry ๐
okay, IANA went shopping in the "Media Types" registry and picked up two brand new Roughtime media types ๐๏ธ
12.4.1. Media Type for Roughtime Server List ๐ง
IANA has allocated the following entry in the "Media Types" registry.
- Type name:
application - Subtype name:
roughtime-server+json - Required parameters:
N/A - Optional parameters:
N/A - Encoding considerations: Encoding considerations are identical to those specified for the "application/json" media type, see [RFC8259].
- Security considerations: Section 9 of RFC 10049.
- Interoperability considerations:
N/A - Published specification: Section 8.3 of RFC 10049.
- Applications that use this media type: Roughtime clients (RFC 10049) that update their lists of Roughtime servers.
- Fragment identifier considerations:
N/A - Additional information:
- Deprecated alias names for this type:
N/A - Magic number(s):
N/A - File extension(s):
N/A - Macintosh file type code(s):
N/A
- Deprecated alias names for this type:
- Person & email address to contact for further information: See Authors' Addresses section of RFC 10049.
- Intended usage:
COMMON - Restrictions on usage:
N/A - Author: See Authors' Addresses section of RFC 10049.
- Change controller: Internet Engineering Task Force
12.4.2. Media Type for Roughtime Malfeasance ๐
IANA has allocated the following entry in the "Media Types" registry.
- Type name:
application - Subtype name:
roughtime-malfeasance+json - Required parameters:
N/A - Optional parameters:
N/A - Encoding considerations: Encoding considerations are identical to those specified for the "application/json" media type, see [RFC8259].
- Security considerations: Section 9 of RFC 10049.
- Interoperability considerations:
N/A - Published specification: Section 8.4.1 of RFC 10049.
- Applications that use this media type: Roughtime clients (RFC 10049) use this media type to report cryptographic proof that a Roughtime server has sent the wrong time.
- Fragment identifier considerations:
N/A - Additional information:
- Deprecated alias names for this type:
N/A - Magic number(s):
N/A - File extension(s):
N/A - Macintosh file type code(s):
N/A
- Deprecated alias names for this type:
- Person & email address to contact for further information: See Authors' Addresses section of RFC 10049.
- Intended usage:
COMMON - Restrictions on usage:
N/A - Author: See Authors' Addresses section of RFC 10049.
- Change controller: Internet Engineering Task Force
13. References ๐
13.1. Normative References
[BCP106] Best Current Practice 106, <https://www.rfc-editor.org/info/bcp106>. At the time of writing, this BCP comprises the following: Eastlake 3rd, D., Schiller, J., and S. Crocker, "Randomness Requirements for Security", BCP 106, RFC 4086, DOI 10.17487/RFC4086, June 2005, <https://www.rfc-editor.org/info/rfc4086>.
[RFC0020] Cerf, V., "ASCII format for network interchange", STD 80, RFC 20, DOI 10.17487/RFC20, October 1969, <https://www.rfc-editor.org/info/rfc20>.
[RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791, DOI 10.17487/RFC791, September 1981, <https://www.rfc-editor.org/info/rfc791>.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.
[RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, DOI 10.17487/RFC3986, January 2005, <https://www.rfc-editor.org/info/rfc3986>.
[RFC4291] Hinden, R. and S. Deering, "IP Version 6 Addressing Architecture", RFC 4291, DOI 10.17487/RFC4291, February 2006, <https://www.rfc-editor.org/info/rfc4291>.
[RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006, <https://www.rfc-editor.org/info/rfc4648>.
[RFC6234] Eastlake 3rd, D. and T. Hansen, "US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)", RFC 6234, DOI 10.17487/RFC6234, May 2011, <https://www.rfc-editor.org/info/rfc6234>.
[RFC8032] Josefsson, S. and I. Liusvaara, "Edwards-Curve Digital Signature Algorithm (EdDSA)", RFC 8032, DOI 10.17487/RFC8032, January 2017, <https://www.rfc-editor.org/info/rfc8032>.
[RFC8085] Eggert, L., Fairhurst, G., and G. Shepherd, "UDP Usage Guidelines", BCP 145, RFC 8085, DOI 10.17487/RFC8085, March 2017, <https://www.rfc-editor.org/info/rfc8085>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.
[RFC8259] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data Interchange Format", STD 90, RFC 8259, DOI 10.17487/RFC8259, December 2017, <https://www.rfc-editor.org/info/rfc8259>.
[RFC9110] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Semantics", STD 97, RFC 9110, DOI 10.17487/RFC9110, June 2022, <https://www.rfc-editor.org/info/rfc9110>.
13.2. Informative References
[Merkle] Merkle, R. C., "A Digital Signature Based on a Conventional Encryption Function", Advances in Cryptology - CRYPTO '87, Lecture Notes in Computer Science, vol. 293, pp. 369-378, DOI 10.1007/3-540-48184-2_32, 1988, <https://doi.org/10.1007/3-540-48184-2_32>.
[RFC0738] Harrenstien, K., "Time server", RFC 738, DOI 10.17487/RFC738, October 1977, <https://www.rfc-editor.org/info/rfc738>.
[RFC5905] Mills, D., Martin, J., Ed., Burbank, J., and W. Kasch, "Network Time Protocol Version 4: Protocol and Algorithms Specification", RFC 5905, DOI 10.17487/RFC5905, June 2010, <https://www.rfc-editor.org/info/rfc5905>.
[RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 8126, DOI 10.17487/RFC8126, June 2017, <https://www.rfc-editor.org/info/rfc8126>.
[RFC8633] Reilly, D., Stenn, H., and D. Sibold, "Network Time Protocol Best Current Practices", BCP 223, RFC 8633, DOI 10.17487/RFC8633, July 2019, <https://www.rfc-editor.org/info/rfc8633>.
[RFC8915] Franke, D., Sibold, D., Teichel, K., Dansarie, M., and R. Sundblad, "Network Time Security for the Network Time Protocol", RFC 8915, DOI 10.17487/RFC8915, September 2020, <https://www.rfc-editor.org/info/rfc8915>.
[RFC9170] Thomson, M. and T. Pauly, "Long-Term Viability of Protocol Extension Mechanisms", RFC 9170, DOI 10.17487/RFC9170, December 2021, <https://www.rfc-editor.org/info/rfc9170>.
[RFC9523] Rozen-Schiff, N., Dolev, D., Mizrahi, T., and M. Schapira, "A Secure Selection and Filtering Mechanism for the Network Time Protocol with Khronos", RFC 9523, DOI 10.17487/RFC9523, February 2024, <https://www.rfc-editor.org/info/rfc9523>.
[RFC9844] Carpenter, B. and R. Hinden, "Entering IPv6 Zone Identifiers in User Interfaces", RFC 9844, DOI 10.17487/RFC9844, August 2025, <https://www.rfc-editor.org/info/rfc9844>.
Appendix A. Example Server List โจ
okay bestie, this appendix is a example Roughtime server list ๐ and it's written in the format from Section 8.3, so go check that section if you want the full rules ๐ง
Here's the vibe: there are two servers in this list. The first is "example.com Roughtime server" and it's reachable over both UDP and TCP on port 5319 ๐ธ The second is a UDP-only server that's listed by IP addresses instead of a name, with one IPv4 address and one IPv6 address, both on port 5319 ๐ฆ The list also has a sources field with two ecosystem URIs and a reports field pointing to a malfeasance URI ๐
{
"servers": [
{
"name": "example.com Roughtime server",
"version": 1,
"publicKeyType": "ed25519",
"publicKey": "2O3mkkheDExCuhG+ZNIoWmO/IdCdLzADgUn8SnC4hME=",
"addresses": [
{
"protocol": "udp",
"address": "roughtime.example.com:5319"
},
{
"protocol": "tcp",
"address": "roughtime.example.com:5319"
}
]
},
{
"name": "A UDP-only server specified with IP addresses",
"version": 1,
"publicKeyType": "ed25519",
"publicKey": "ZYfeGa94YuG1IZrV3kR9+8/nmZ2lX2XyHmiSb+wI0OY=",
"addresses": [
{
"protocol": "udp",
"address": "192.0.2.33:5319"
},
{
"protocol": "udp",
"address": "[2001:db8::2:33]:5319"
}
]
}
],
"sources": [
"https://www.example.net/roughtime/ecosystem.json",
"https://www.example.org/roughtime/ecosystem.json"
],
"reports": "https://www.example.net/roughtime/malfeasance"
}
Appendix B. Example Malfeasance Report ๐ฅ
this appendix is giving receipts ๐ It shows an example Roughtime malfeasance report in the format from Section 8.4.1, and it has enough info to prove that the server with the public key lRhHag6fn2wZQ6idy10ChgpRgks3gvdMM2hWNeJNgXg= gave a time that doesn't match the times reported by the other two servers ๐
the report is the proof, so every single character matters here, no cap ๐ซถ
{
"responses": [
{
"publicKey": "FnDyLV/68ephhLdFJbdEGCdkVvpXDaVe5PYvRDdlOOY=",
"request": "Uk9VR0hUSU0ABAAABQAAAAQAAAAkAAAARAAAAEgAAABWRVIAU1JW
AE5PTkNUWVBFWlpaWgEAAACf4gKLPdPfiNTv93lrhNqYgyehDgMyHFmA1BrAhM1QEDBh9l
BlN6LUye6zghiqSWMwyNm0IucxQxW3zTMrwj4dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
==",
"response": "Uk9VR0hUSU2UAQAABwAAAEAAAABgAAAAZAAAAGQAAADAAAAAWAE
AAFNJRwBOT05DVFlQRVBBVEhTUkVQQ0VSVElORFhBWL64CToGs4v/4UtfN/80HLFiA09vG
IDRP/zTjcTj8/1DlZWCsVja6RlfwaYnc1wfJqThfhcuSDonrTGyKngBMGH2UGU3otTJ7rO
CGKpJYzDI2bQi5zFDFbfNMyvCPh0BAAAABQAAAAQAAAAIAAAAEAAAABQAAABWRVIAUkFES
U1JRFBWRVJTUk9PVAEAAAADAAAAQ0u4aQAAAAABAAAAc86AWYB/O3Kxzsx4d5P5cbSOftJ
UA8bWVtVrQ3tc+b0CAAAAQAAAAFNJRwBERUxFI2B5tbj5ePjVKYE0PAL1NmgZOAsqh/E2f
rom9Ol5BAnVcLje0C6exbXY8hE3dRvYV01Alru8Ocle+jOZT5r8AwMAAAAgAAAAKAAAAFB
VQktNSU5UTUFYVKqljhhqi4A54vW20e+slwViPyxybNnqKXzimIiIUHQMaBCvaQAAAADYy
d9pAAAAAAAAAAA="
},
{
"publicKey": "l9cdSuR8dFxtG9aJo9pWzUXaX8pftNG4UDC45Qk3znc=",
"rand": "v/DirVBRQLGtictYD7mN3px02UlMT4J3haTRomt1NNM=",
"request": "Uk9VR0hUSU0ABAAABQAAAAQAAAAkAAAARAAAAEgAAABWRVIAU1JW
AE5PTkNUWVBFWlpaWgEAAABFCvadUKPN/U9OXqFalVFnv/EhsAuPPpBYfo5MDULZKv335k
bNTZcsYLM96o77yLbvvRk1fm2TQB4yKxbP1jzeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
==",
"response": "Uk9VR0hUSU2UAQAABwAAAEAAAABgAAAAZAAAAGQAAADAAAAAWAE
AAFNJRwBOT05DVFlQRVBBVEhTUkVQQ0VSVElORFj+2I02cCBAfDYzP+8znW6bICqVrAF23
xNLfM+Qycmkpfp1+BQSb4l/6mRll66l2VIfPSQzigl2V5OJgQzGEBcG/ffmRs1Nlyxgsz3
qjvvItu+9GTV+bZNAHjIrFs/WPN4BAAAABQAAAAQAAAAIAAAAEAAAABQAAABWRVIAUkFES
U1JRFBWRVJTUk9PVAEAAAADAAAAw/m2aQAAAAABAAAAS8ROJoXIPSlO9yN+uREb+/UiOJJ
qCjx3VWZ/vD2FqBMCAAAAQAAAAFNJRwBERUxFw0MFQMiDoHySot8rlnV83Vqaa3qTrAY15
W1TzqNuAurOvreNw08BfUwxF7BQ/b/JCwCQcqtD5uRYsvikvuyLCwMAAAAgAAAAKAAAAFB
VQktNSU5UTUFYVCQs/eCxtWjVrXyse0SeojyZdNFkOwe3B3nLHtHJZK/9gRCvaQAAAADxy
d9pAAAAAAAAAAA="
},
{
"publicKey": "lRhHag6fn2wZQ6idy10ChgpRgks3gvdMM2hWNeJNgXg=",
"rand": "lMvMVoLsakxc5ZmMzEFQ8hh1FaDo2gCXXIX/L4QPSxQ=",
"request": "Uk9VR0hUSU0ABAAABQAAAAQAAAAkAAAARAAAAEgAAABWRVIAU1JW
AE5PTkNUWVBFWlpaWgEAAADmAab6GlTSr3xRmwwwvRjW6EKRhtyWYYWZHZIGnF8w2b4DuI
ICvoCWTwCaupBfcOEwV+RqBWB6L1JUGn+ot8+9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
==",
"response": "Uk9VR0hUSU2UAQAABwAAAEAAAABgAAAAZAAAAGQAAADAAAAAWAE
AAFNJRwBOT05DVFlQRVBBVEhTUkVQQ0VSVElORFg8MlhdCJeQ2qzN6b9q646W9kB+XmAdS
g7ToU1gj3AD8AP8eCHfduMBE0E8j4/LqWIr72zWQx8Y1U/1uxs97yMAvgO4ggK+gJZPAJq
6kF9w4TBX5GoFYHovUlQaf6i3z70BAAAABQAAAAQAAAAIAAAAEAAAABQAAABWRVIAUkFES
U1JRFBWRVJTUk9PVAEAAAADAAAAw/m2aQAAAAABAAAA6ho4+0Cml+VJbqU7hsF717uusV2
HYvRbU9CdjJE/Zn0CAAAAQAAAAFNJRwBERUxFM9Fvq8T9kOrxcS7jviCPHe44HX/75Je1h
afPJ0f8NoASy29EgD7C0c/LMxXiXxEwyuxYTPN9oseAr9XIt68uDwMAAAAgAAAAKAAAAFB
VQktNSU5UTUFYVMxBDiNG247IO4onsGcjFHsA3vP+arl+s0lBLhXw0c1RlBCvaQAAAAAEy
t9pAAAAAAAAAAA="
}
]
}
Acknowledgments ๐
big thank-you moment ๐ซถ Aanchal Malhotra and Adam Langley wrote early draft versions of this document, which is iconic of them ๐
Then there's a whole squad who helped out: Daniel Franke, Sarah Grant, Erik Kline, Martin Langer, Ben Laurie, Peter Lรถthberg, Michael McCourt, Hal Murray, Tal Mizrahi, Ruben Nijveld, Christopher Patton, Thomas Peterson, Rich Salz, Dieter Sibold, Ragnar Sundblad, Kristof Teichel, Luke Valenta, David Venhoek, Ulrich Windl, and the other members of the NTP Working Group. They left comments and suggestions, and they also caught errors, which is literally the best kind of friend ๐ง
The authors also want to thank the Last Call reviewers and members of the IESG for their helpful comments and suggestions ๐
Authors' Addresses ๐ฆ
Watson Ladd
- Akamai Technologies
- Email:
watsonbladd@gmail.com
Marcus Dansarie
- Netnod
- Email:
marcus@dansarie.se - URI:
https://orcid.org/0000-0001-9246-0263
๐ฆ where this page comes from
- ietf: rfc10049 2026-10
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms