<?xml version="1.0" encoding="utf-8"?>
<rfcdesc title="Roughtime: A Protocol for Rough Time Synchronization" num="10049" status="experimental" wg="ntp">
  <authors><author>W. Ladd (Akamai
  Technologies)</author><author>M. Dansarie
  (Netnod)</author></authors>
  <date>2026-10-07</date>
  <rfcdate><month>October</month><year>2026</year></rfcdate>
<content>
  <p>Ce nouveau protocole de synchronisation d'horloges,
  Roughtime est, officiellement, encore
  expérimental. Deux de ses buts essentiels sont la possibilité d'une
  synchronisation sécurisée (avec de la cryptographie, donc), même
  quand le client n'a aucune idée de l'heure et du jour, et un moyen
  de signaler les erreurs et problèmes rencontrés. Il concernera
  notamment les objets connectés qui, souvent, n'ont pas de batterie
  pour garder l'heure pendant un arrêt.</p>
  <p>Si vous connaissez <wikipedia name="Network Time
  Protocol">NTP</wikipedia> (<rfc num="5905" local="true"/>), vous
  savez qu'il n'offre pas de solution à ces deux problèmes. Roughtime
  est donc une alternative à NTP.</p>
  <p>La synchronisation des horloges est un problème très ancien sur
  l'Internet (cf. <rfc num="738"/>). Elle est à la fois cruciale,
  notamment en sécurité, et très difficile à réaliser. Pour comprendre
  son importance en sécurité, pensez par exemple à l'estampillage de
  <wikipedia name="Historique (informatique)">journaux</wikipedia>. Ou aux signatures <wikipedia
  name="Domain Name System Security Extensions">DNSSEC</wikipedia>. Ou
  à <wikipedia name="Mot de passe à usage unique basé sur le temps">TOTP</wikipedia> (<rfc num="6238" local="true"/>). Ou
  encore à la vérification qu'un <wikipedia name="Certificat électronique">certificat</wikipedia>
  n'est pas expiré. Mais c'est justement aussi cela qui rend difficile
  de la sécuriser. <wikipedia name="Network Time
  Protocol">NTP</wikipedia> a un mécanisme de sécurité, NTS, normalisé
  dans le <rfc num="8915" local="true"/>, mais qui <link
  url="https://mailarchive.ietf.org/arch/msg/last-call/tCWzj0vGowUeNfC6ioO8VUtUGPM">dépend
  d'un certificat</link>, donc d'avoir l'heure correcte. C'est un
  intéressant <wikipedia name="Paradoxe de l'œuf et de la poule">problème d'œuf et de poule</wikipedia> : pour
  vérifier le certificat du serveur de temps, vous avez besoin de
  connaitre l'heure, justement ce que vous vouliez demander au serveur
  (section 6 du RFC).</p>
  <p>Roughtime, spécifié dans ce <rfc
  num="10049"/>, résoud le problème en partant d'une
  <emphasis>liste</emphasis> de serveurs et de leurs <wikipedia
  name="Cryptographie asymétrique">clés
  publiques</wikipedia>. Celles-ci sont censées durer assez longtemps
  pour que, dans la liste des serveurs, il y en ait plusieurs qui
  soient correctes. En prime, l'utilisation de réponses <wikipedia
  name="Signature numérique">signées</wikipedia> par les serveurs
  Roughtime permet à un client de prouver à un tiers qu'un serveur est
  malveillant (ou complètement déconnant ; on ne peut pas distinguer
  les deux cas). Le client obtient cette preuve en chainant les
  réponses de plusieurs serveurs. J'insiste : si on n'utilise qu'un
  seul serveur Roughtime, le client ne peut pas être sûr que l'heure
  obtenue est correcte. La sécurité ne vient que lorsqu'on a
  « suffisamment » de serveurs. (Évidemment, s'ils sont tous
  malveillants ou déconnants, on est fichu. Comme dit lors d'une
  discussion <wikipedia name="Internet Engineering Task
  Force">IETF</wikipedia>, « <foreign>Ideally, you would use 3 servers
  run by 3 different organizations using 3 different software
  implementations running on 3 different operating systems in 3
  different well guarded buildings in 3 different
  countries...</foreign> ».) Cette possibilité de prouver à un tiers
  qu'un des serveurs ne servait pas l'heure correcte est une
  importante différence avec un autre concurrent de NTP,
  Khronos (<rfc num="9523"
  local="false"/>).</p>
  <p>Ce RFC décrit le format des paquets et le protocole mais pour que
  Roughtime sorte de son statut expérimental, il faudra aussi déployer
  un écosystème de serveurs et un mécanisme pour obtenir une liste
  (avec les clés, souvenez-vous). Aucune méthode n'est prévue pour
  l'instant pour changer les clés, il faudra donc vraiment qu'elles
  durent longtemps, ou que l'objet connecté puisse facilement mettre à
  jour de manière sécurisée sa liste de serveurs.</p>
  <p>La section 3 du <wikipedia name="Request for
  comments">RFC</wikipedia> décrit le protocole en termes
  généraux. <wikipedia name="Signature numérique">Signer</wikipedia>
  les réponses n'est pas suffisant car il faut aussi que la réponse
  dépende de la requête du client (pour qu'il s'assure qu'on ne lui
  serve pas une vieille réponse rassise) et qu'on puisse la chainer
  avec celle des autres serveurs (via le classique <wikipedia name="Arbre de Merkle">arbre de
  Merkle</wikipedia>), pour qu'un tiers puisse repérer le serveur qui
  ne répond pas correctement.  S'il n'y a qu'un serveur utilisé, le
  client peut tout juste vérifier que le message est correctement
  signé, et correspond à la question (celle-ci inclut un <link
  local="nonce">numnique</link>) mais s'il y en a plusieurs, le client
  peut les comparer et repérer un serveur qui est trop à l'écart (que
  ce soit par erreur ou par malveillance, en général, on ne peut pas
  distinguer les deux). Une fois le serveur anormal repéré, on peut le
  signaler sur un forum, le faire virer des listes de serveurs qui
  circulent, etc.</p>
  <p>La section 4 décrit le format des messages. Parmi les points à
  noter, la notion d'étiquette (<foreign>tag</foreign>). Les valeurs
  transportées sont toutes étiquetées, chaque étiquette étant sur
  quatre octets, en général choisis pour être une valeur en <wikipedia
  name="American Standard Code for Information
  Interchange">ASCII</wikipedia>. NONC va ainsi indiquer que la valeur
  qui suit est le numnique (<foreign>nonce</foreign>), VER (avec un
  octet nul à la fin) indique la version (actuellement <link
  url="https://www.iana.org/assignments/roughtime#roughtime-versions">version
  1</link>), etc. Les étiquettes connues figurent dans <link
  url="https://www.iana.org/assignments/roughtime#roughtime-tags">un
  registre IANA</link> et on peut en ajouter selon la politique
  « Spécification nécessaire » du <rfc num="8126" local="true"/>.</p>
  <p>Autre notion cruciale, les valeurs temporelles
  (<foreign>timestamp</foreign>) sont un entier sur 64 bits, indiquant
  le nombre de secondes depuis le 1 janvier 1970. Le message complet
  est composé d'un <wikipedia name="Nombre magique (programmation)">nombre magique</wikipedia>
  (0x4d49544847554f52, ce qui fait "ROUGHTIM"), du nombre de valeurs,
  d'une liste de décalages des valeurs, d'une liste d'étiquettes, puis
  des valeurs. Les deux listes sont triées selon l'ordre des
  étiquettes. La première valeur a pour décalage zéro.</p>
  <p>Le message est ensuite transmis en <wikipedia name="User Datagram
  Protocol">UDP</wikipedia> (avec du
  remplissage obligatoire pour éviter les
  attaques avec amplification, section 9.7 du RFC). L'algorithme
  cryptographique est forcément <wikipedia>Ed25519</wikipedia>, décrit
  dans le <rfc num="8032" local="true"/>. Il n'y a pas d'agilité
  cryptographique - <rfc num="7696" local="true"/>, il faudra changer
  de version du protocole pour, par exemple, passer à la
  <wikipedia name="Cryptographie post-quantique">cryptographie post-quantique</wikipedia> (section
  9.5). Dans une requête, les étiquettes VER (version du protocole),
  NONC (le numnique du client, qui doit évidemment être aussi
  imprédictible que possible, cf. <rfc num="4086" local="true"/>) et
  TYPE (0 pour une requête) sont obligatoires. On peut y ajouter SRV,
  qui indique la clé publique que le client compte utiliser (cela
  permet au serveur, entre autres, de sélectionner la bonne clé si on
  en a plusieurs, mais aussi de voir qu'un client a toujours une
  vieille clé).</p>
  <p>La réponse a les étiquettes NONC (celui qui avait été envoyé par
  le client), TYPE (1 pour une réponse), SIG (la signature du
  message), PATH (des valeurs de l'<wikipedia name="Arbre de Merkle">arbre de
  Merkle</wikipedia>), CERT (un <wikipedia name="Certificat électronique">certificat</wikipedia>) et
  SREP (la partie utile de la réponse). La valeur associée à
  l'étiquette SREP est elle-même un message Roughtime avec notamment
  les étiquettes MIDP (l'heure sur le serveur, c'est-à-dire
  l'information principale pour le client), RADI (une estimation de la
  précision de l'heure, en secondes) et ROOT (la racine de l'arbre de
  Merkle, qui sera utilisé si on interroge plusieurs serveurs,
  cf. section 5.3).</p>
  <p>On peut noter qu'il n'existe pas de réponse pour une requête
  erronée (pas de FORMERR comme dans le <wikipedia name="Domain Name
  System">DNS</wikipedia> ou de <foreign>Kiss o' Death</foreign> comme
  dans <wikipedia name="Network Time
  Protocol">NTP</wikipedia>). L'expérience de NTP (section 7.4 du <rfc
  num="5905" local="true"/>, section 5.4 du <rfc num="8633"
  local="true"/> et section 8.3 et 8.7 du <rfc num="8915"
  local="true"/>) est que cela facilite trop certaines attaques par
  déni de service en faisant croire qu'un serveur a un problème.</p>
  <p>Pour éviter l'<wikipedia name="Ossification des
  protocoles">ossification</wikipedia> du protocole, la section 7 du
  RFC demande de graisser (<rfc num="9170" local="true"/>) les
  réponses en envoyant de temps en temps des réponses invalides
  (absence d'étiquettes obligatoires, par exemple, présence
  d'étiquettes non définies et surtout heures délibérement incorrectes
  mais avec des signatures invalides ; un client bien fait ignorera
  ces réponses, les autres se feront tromper).</p>
  <p>Côté client, maintenant, le protocole prévoit que le client
  vérifie les signatures et signale (par un moyen non normalisé) les
  serveurs qui s'écarteraient trop des autres. La section 8.4 décrit
  un format en <wikipedia name="JavaScript Object
  Notation">JSON</wikipedia> pour produire des rapports, au type
  <computer>application/roughtime-malfeasance+json</computer> (avec un
  exemple dans l'annexe B) mais, pour l'instant, il n'y a pas
  grand'chose de spécifié et encore moins de déployé.</p>
  <p>Notez que, si les réponses sont signées, Roughtime ne fournit en
  revanche aucune <wikipedia>confidentialité</wikipedia>.</p>
  <p>Sur ma machine au logiciel pas tout à fait récent,
  <wikipedia>Wireshark</wikipedia> ne connait pas encore Roughtime
  mais, quand on analyse un paquet, on voit bien la liste des
  étiquettes :
  <code>
<![CDATA[
Frame 10: 434 bytes on wire (3472 bits), 434 bytes captured (3472 bits)
…
User Datagram Protocol, Src Port: 2002, Dst Port: 47639
Data (392 bytes)

0000  52 4f 55 47 48 54 49 4d 7c 01 00 00 07 00 00 00   ROUGHTIM|.......
0010  40 00 00 00 44 00 00 00 64 00 00 00 64 00 00 00   @...D...d...d...
0020  a8 00 00 00 40 01 00 00 53 49 47 00 56 45 52 00   ....@...SIG.VER.
0030  4e 4f 4e 43 50 41 54 48 53 52 45 50 43 45 52 54   NONCPATHSREPCERT
0040  49 4e 44 58 73 d4 d3 56 32 f7 d1 03 28 31 35 bf   INDXs..V2...(15.
0050  18 14 ea 6e 62 74 99 58 ca b2 85 bf 1f 0b ca a1   ...nbt.X........
0060  4e 06 1c 4a ea 0b e0 9c 93 12 5b 7d 79 23 16 c3   N..J......[}y#..
0070  32 d9 41 d9 b0 94 5b 68 c0 e3 f1 c3 61 ab 00 6f   2.A...[h....a..o
0080  58 a8 d9 0c 0b 00 00 80 ac 90 f3 d2 69 b9 f8 d6   X...........i...
0090  7a 0d b7 37 42 e3 27 ab ed e3 fb d2 e8 41 f9 25   z..7B.'......A.%
00a0  75 de be 60 0a d6 59 80 03 00 00 00 04 00 00 00   u..`..Y.........
00b0  0c 00 00 00 52 41 44 49 4d 49 44 50 52 4f 4f 54   ....RADIMIDPROOT
00c0  03 00 00 00 3c 2c c6 6a 00 00 00 00 28 68 0c 3e   ....<,.j....(h.>
00d0  99 9c 8d c3 1c 86 9b 1f b9 05 4b 3d a5 92 0d 4c   ..........K=...L
00e0  48 4f a0 7c 16 ae e4 1e 0b 24 2e d1 02 00 00 00   HO.|.....$......
00f0  40 00 00 00 53 49 47 00 44 45 4c 45 cc 05 f4 6c   @...SIG.DELE...l
0100  56 46 12 eb 4d 45 47 c9 77 21 f4 9b 78 8f 46 2c   VF..MEG.w!..x.F,
0110  fa e1 08 8b 49 40 2e 70 e2 c3 15 f1 fe 2e 50 ab   ....I@.p......P.
0120  00 ab 77 18 3e f2 e0 56 7b 41 9a 39 78 de 4a e4   ..w.>..V{A.9x.J.
0130  aa 8d bf c8 79 b3 f9 86 75 8a 18 0f 03 00 00 00   ....y...u.......
0140  20 00 00 00 28 00 00 00 50 55 42 4b 4d 49 4e 54    ...(...PUBKMINT
0150  4d 41 58 54 b4 f2 07 3c f9 a5 f4 f0 d2 e5 03 51   MAXT...<.......Q
0160  1a cb b0 31 2f e3 cd 83 b7 14 ef 64 eb bb 9c 3b   ...1/......d...;
0170  4c 69 3a ea dc 8e c5 6a 00 00 00 00 5c e0 c6 6a   Li:....j....\..j
0180  00 00 00 00 00 00 00 00                           ........
    Data [truncated]: 524f55474854494d7c0100000700000040000000440000006400000064000000a80000004001000053494700564552004e4f4e4350415448535
2455043455254494e445873d4d35632f7d103283135bf1814ea6e62749958cab285bf1f0bcaa14e061c4aea0be09c93125b7d79231
    [Length: 392]
]]>
  </code>
  </p>
 <p>Voyons maintenant les mises en œuvre concrètes de ce protocole,
 côté client et côté serveur. D'abord, un avertissement : le RFC vient
 de sortir, le projet de norme a eu plusieurs itérations et vous
 trouverez donc en ligne divers programmes qui n'interagissent pas
 toujours entre eux (par exemple, le logiciel client de
 <wikipedia>Cloudflare</wikipedia> ne fonctionne pas <link
 url="https://github.com/cloudflare/roughtime/issues/72">avec le
 serveur public de Cloudflare</link><!-- Doc
 https://developers.cloudflare.com/time-services/roughtime/usage/
 -->). Il faudra donc attendre un peu que tout soit d'équerre. En
 attendant, jouons un peu. D'abord, le <link
 url="https://github.com/cloudflare/roughtime">logiciel de
 Cloudflare</link>, écrit en <wikipedia name="Go
 (langage)">Go</wikipedia> (vous pouvez aussi <link
 url="https://developers.cloudflare.com/time-services/roughtime/">lire
 leur documentation</link>) :
 <code>
% git clone https://github.com/cloudflare/roughtime.git
% cd roughtime
% cd cmd/getroughtime
% go build main.go
% ./main 
Either provide a configuration via -config or an address via -ping
 </code>
 Ah, c'est logique, rappelez-vous ce que j'ai écrit sur la liste de
 serveurs (et leurs clés, cf. sections 8.1 et 8.3 du
 RFC). getroughtime sait utiliser une liste écrite en <wikipedia
 name="JavaScript Object Notation">JSON</wikipedia>. Le RFC décrit le
 format dans sa section 8.3, et on utilise le
 <wikipedia name="Type de médias">type</wikipedia>
 <computer>application/roughtime-server+json</computer> si on la
 distribue en ligne. Un exemple figure dans l'annexe A. Il y a une
 liste fournie dans le logiciel, utilisons-la :
 <code>
% ./main -config ../../ecosystem.json
skipped Cloudflare-Roughtime-2: protocol: response is missing NONC tag
skipped int08h-Roughtime: no reply
skipped roughtime.se: no reply
time.txryan.com: 2026-10-06 09:36:47 +0000 UTC ±3s (in 96ms)
Delta: -741ms
 </code>
 Bon, plusieurs des serveurs ne répondent pas, ou pas correctement
 selon les clients (ma remarque ci-dessus à propos des différentes
 versions qui trainent). Mais le dernier marche, et on a bien
 l'heure. Le même logiciel contient aussi un serveur de test :
 <code>
% cd ../testserver
% go build main.go
% ./main  
main.go:64: Root public key: zFVzPprRDxDOMdsrifp+/XPkVkDEhllv6QDJxOWWYd0=
 </code>
 Le serveur tourne (par défaut, sur
 <computer>127.0.0.1:2002</computer>). Notez que le
 <wikipedia name="Port (logiciel)">port</wikipedia> officiellement <link
 url="https://www.iana.org/assignments/service-names-port-numbers?search=1&amp;page=44">enregistré
 à l'IANA</link> est désormais 5319. Et le serveur nous affiche sa
 clé. Essayons en indiquant cette clé :
 <code>
% cd ../getroughtime
% ./main -ping localhost:2002 -pubkey zFVzPprRDxDOMdsrifp+/XPkVkDEhllv6QDJxOWWYd0=
Ping response: 2026-10-06 11:37:57.754243 +0200 CEST ±1s (in 1ms)
 </code>
 Parfait, tout va bien. Si on avait indiqué une mauvaise clé :
 <code>
% ./main -ping localhost:2002 -pubkey kMe//FBOFOwPXjx8NYjPtkdlH94IoxAX98RDsiVXcEc=
Ping error: protocol: invalid delegation signature
 </code>
 Le client vérifie donc bien les signatures du serveur. Essayons avec
 <link url="https://github.com/nahojkap/craggy">un autre
 logiciel</link>, écrit en <wikipedia name="C (langage)">C</wikipedia> :
 <code>
% git clone https://github.com/nahojkap/craggy.git
% cd craggy
% cmake -E make_directory ./build
% cmake -S . -B ./build/ -DCRAGGY_WITH_ORLP_ED25519_BINDINGS=ON
% cd build
% make
 </code>
 Le client ne fonctionne pas avec le serveur de test de Cloudflare
 (qui meurt avec « <foreign>main.go:97: Error while handling request:
 no version in common: []</foreign> ») mais il marche avec au moins un
 serveur public :
 <code>
% ./cli/craggy-cli -h  time.txryan.com:2002 -k iBVjxg/1j7y1+kQUTBYdTabxCppesU/07D4PMDJk2WA=

Received reply in 105898μs. (105ms)
Current time is 1791281389ms from the epoch, ±3s 
System clock differs from that estimate by -796785μs. (-796ms)
 </code>
  Il existe aussi d'autres mises en œuvre que je n'ai pas testées,
  <link url="https://roughtime.googlesource.com/roughtime">chez
  Google</link> en Go, <link
  url="https://github.com/oreparaz/vroughtime">une autre</link> en C
  et <link
  url="https://blog.sturdystatistics.com/posts/roughtime/">une
  dernière</link>, en <wikipedia>Clojure</wikipedia>. Si vous cherchez
  des serveurs publics pour tester, vous avez <link
  url="https://github.com/cloudflare/roughtime/blob/master/ecosystem.json">une
  liste</link> (pas à jour…) dans le code de Cloudflare. Ou bien vous
  en trouvez quelque part sur le réseau, par exemple le <link
  url="https://rough.time.nl/">serveur expérimental de SIDN</link>. Je
  copie la configuration qu'ils indiquent, je l'édite pour changer la
  version en <computer>IETF-Roughtime</computer> (car le client testé ne
  connait pas encore la version 1) et ça marche avec le logiciel de
  Cloudflare :
  <code>
% ./main -config /tmp/sidn.json
TimeNL-Roughtime: 2026-10-07 17:06:30 +0200 CEST ±3s (in 24ms)
Delta: -658ms
  </code>
</p>
  <p>Autres lectures :
  <enum>
    <item>L'<link
    url="https://blog.cloudflare.com/roughtime/">explication de
    Cloudflare</link> et <link
    url="https://developers.cloudflare.com/time-services/roughtime/">la
    documentation du logiciel</link>,</item>
    <item>une courte <link
    url="https://labs.ripe.net/author/robert-allen/roughtime-securing-time-for-iot-devices/">explication
    claire des buts du protocole</link> par un des auteurs du RFC<!--
    Roughtime: Securing Time for IoT Devices --> et une <link
    url="https://www.ripe.net/media/documents/RIPE_Open_House_May_2024_Netnod_Roughtime_v.1.pdf">présentation
    qu'il avait faite au RIPE</link> pendant le développement du
    protocol,</item>
    <item>la vidéo d'une <link
    url="https://ripe87.ripe.net/archives/video/1175/">autre
    présentation du projet</link>,</item>
    <item>le résultat des <link
    url="https://labs.ripe.net/author/robert-allen/securing-time-for-any-device-results-from-the-roughtime-hackathon-at-ietf-121/">tests
    du protocole à un hackathon de l'IETF en 2024</link>,</item>
    <!-- Le site roughtime.se présente un serveur public mais qui
	 aujourd'hui ne répond pas. -->
  </enum>
  </p>
</content>
</rfcdesc>
