時刻同期プロトコル Roughtime の標準化

Rougtime」という時刻同期プロトコルの標準化が進められている。

すでに、GoogleやCloudflareがRoughtimeサーバを公開している

  • roughtime.cloudflare.com
  • roughtime.sandbox.google.com

もともとは、2016年頃にGoogleのAdam Langley氏が原案を公開しており、サーバの実装が進められた。その後、時刻同期プロトコルを扱うIETFのNTP WGに仕様が提出されました。そして2020年1月に、「Rougtime」としてWG Draftになり標準化が進められています。

Roughtimeプロトコルの特徴

Roughtimeは以下の特徴を持つ

  • クライアントからリクエストを送信し、サーバから署名を付けてレスポンス(時刻+証明書+署名)を返す
  • 複数サーバを利用することで、暗号的に不正なサーバを暗号的に検知できる
  • UDPTCPに対応。UDPでは、アンプ攻撃対策が入ってる。
  • サーバにおける署名処理は、複数クライアントからのリクエストを一気に署名できるようになっている
  • バッチ的に処理を行うため、高精度の時刻同期ではない

f:id:ASnoKaze:20200412230149p:plain:w480
(図はリクエスト/レスポンス内に含まれるタグを一部咲楽しています)

Rougtimeでは、クライアントからリクエストを送り、サーバから署名のついたレスポンスが返されます。サーバの署名がついてますので、クライアントはサーバを認証できます。

クライアントはリクエストにノンス(NONC)をつけて送ります。これに対してサーバ側はレスポンス(時刻+証明書+ノンスに対する署名 SIG)を返します。これにより、クライアントからのリクエストを受信したあとに、レスポンスが生成されたことを暗号的に保証することができます。

クライアントはサーバAからのレスポンスを、乱数と結合しハッシュを撮った値を付きのサーバBへのノンスとして送ります。こうすることで、「サーバAからの時刻 < サーバBからの時刻」ということことが暗号的に保証されます。こうすることで、暗号的に不正な値を返すサーバを見つけることができます。

各サーバは事前に長期鍵として公開鍵を公開している。その鍵で一時鍵を署名して、その一時鍵を用いてクライアントからのリクエストに対して署名処理をする。

例えば、Cloudflareでは長期鍵はこのように公開されています。

   address:       roughtime.cloudflare.com
   port:          2002
   long-term key: gD63hSj3ScS+wuOeGrubXlq35N1c5Lby/S+T7MNTjxo=

メッセージ

リクエストおよび、レスポンスのメッセージは下記の構造を持ちます。タグというキー・バリューのペアが複数含まれます。

最初にタグの数と、メッセージの中で1~N番目のタグがどこから始まるか示すオフセット、32bitのタグ(ASCIIでNONCやVERのように表現されます)およびタグの値が繰り返されます。

f:id:ASnoKaze:20200412231215p:plain

リクエス

リクエストは以下のタグを持ちます

  • NONC: ノンス
  • VER: プロトコルバージョン
  • PAD: UDPの場合は、アンプ攻撃を防ぐためリクエストメッセージが1024バイトを超えるようにパディングをします
レスポンス

レスポンスには、時刻を示すMIDP、証明書を示すCERT、署名値SIGとマークルツリー(後述) ROOT INDEX PATHなどである。

署名対象はSREPであり、ここに時刻やマークルツリーのROOTの値の値が含まれている。複数のリクエストを一度に処理する場合、このPREPが同じ値になる。

Response

  • SREP
    • ROOT: リクエストとの署名値を含むマークルツリーのルート値
    • MIDP: 処理の瞬間のタイムスタンプ
    • RADI: MIDPの制度を示す値 MIDP - RADI < MIDP < MIDP + RADI になる。
    • NONC: リクエストのノンス
    • LEAP: うるう秒情報
  • SIG: 署名 (signature contextとSREPかDELEを結合したものを、署名したもの)
  • CERT: サーバーの長期鍵で署名された公開鍵証明書
  • DELE: サーバーがSREPタグに署名するために使用する委任された公開鍵証明書が含まれています。
  • MINT: PUBKが信頼される最低時間(MIDP)
  • MAXT: PUBKが新楽される最高時間(MIDP)
  • PUBK: SREPタグの署名に使用される一時鍵
  • INDEX: マークルツリー内のNONCの位置
  • PATH: マークルツリー内のNONCからROOTへのパス (各ノードの32バイトハッシュ値の羅列)
  • VER: バージョン

署名のバッチ処理

Routhtimeでは、サーバは複数のリクエストのノンスに対して一度に署名処理を行います。これは、先述のマークルツリーを利用します。

ツリーの各リーフには、複数のクライアントから送られてきたノンス(NONC)が含まれます。各リーフは左から順にindexを持ちます。

親は、左のノードと右のノードを結合しハッシュを取った値が含まれています。

順々にハッシュを取ってルートが計算されると、ルートの値と時刻情報を合わせて署名を行います。その署名結果を複数のリクエストに対するレスポンスに含めます。

f:id:ASnoKaze:20200412235758p:plain

クライアントは署名値を検証するのにマークルツリー全体の情報は必要なく、自身の送ったノンス(NONC)のindex, ROOT, およびPATH(ROOTまでハッシュを計算するのに必要なノードの値)のみが必要です。

例えば、index3のPATHは赤く囲ったノードになります。