メインコンテンツまでスキップ

付録C. 認証の問題

この付録は、NTPメッセージの完全性を検証し、メッセージの変更やリプレイ攻撃に対する保護を提供するために使用できるオプションの認証メカニズムについて説明しています。このメカニズムはMD5暗号ハッシュ関数に基づいており、ピア間で共有秘密鍵を使用します。認証が有効な場合、鍵識別子とメッセージダイジェストを含む認証子フィールドがNTPメッセージに追加されます。

認証メカニズムは以下のセキュリティサービスを提供します:

  1. メッセージ完全性: メッセージが転送中に変更されていないことを保証します。
  2. ソース認証: メッセージが共有秘密鍵を持つ正当なピアから発信されたことを検証します。
  3. リプレイ保護: NTPタイムスタンプメカニズムと組み合わせると、リプレイ攻撃に対する保護を提供します。

認証メカニズムはオプションであり、すべての場合に実装する必要はありません。ただし、特に不正なタイムサーバーが誤った時刻情報を注入する可能性がある環境では、セキュリティが懸念される場合、認証メカニズムは効果的な保護手段を提供します。

C.1. NTP認証メカニズム

NTP認証メカニズムは、MD5暗号ハッシュ関数を使用して、NTPメッセージと共有秘密鍵に対するメッセージダイジェストを計算します。メッセージダイジェストは、使用された鍵を指定する鍵識別子とともに、NTPメッセージの認証子フィールドに追加されます。

認証子フィールドは以下の形式です:

 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Key Identifier |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| Message Digest |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

鍵識別子: これは、メッセージダイジェストの生成に使用された暗号鍵を識別する32ビット符号なし整数です。

メッセージダイジェスト: これは、NTPメッセージ(認証子フィールドを含まないまで)と共有秘密鍵に対して計算された128ビットMD5ハッシュです。

共有秘密鍵は手動で構成され、NTPデーモンがアクセスできる鍵ファイルに保存されます。各鍵には一意の識別子があり、64ビット(8オクテット)値として表されます。鍵の形式はDES暗号化アルゴリズムと互換性がありますが、認証メカニズムではDESは直接使用されません。

C.2. NTP認証手順

認証手順は送信および受信操作中に呼び出されます。認証が有効な場合、送信手順はメッセージダイジェストを計算し、送信メッセージに認証子を追加します。受信手順は受信メッセージの認証子を検証し、それに応じて認証ビットを設定します。

C.2.1. 暗号化手順

認証が有効な場合、送信手順から暗号化手順が呼び出されます。これはMD5メッセージダイジェストを計算し、NTPメッセージに認証子を追加します。

begin encrypt procedure
if (peer.authenable = 0) exit; /* 認証無効 */

/* 鍵識別子を追加 */
pkt.keyid <- peer.hostkeyid;

/* メッセージと鍵に対してMD5ダイジェストを計算 */
digest <- MD5(message || key[peer.hostkeyid]);

/* メッセージにダイジェストを追加 */
pkt.check <- digest;

end encrypt procedure

MD5計算は、NTPメッセージ全体(NTPヘッダーとタイムスタンプフィールドを含む)に続いて共有秘密鍵に対して実行されます。結果の128ビットダイジェストは、認証子フィールドのメッセージに追加されます。

C.2.2. 復号化手順

受信メッセージの認証子を検証するために、受信手順から復号化手順が呼び出されます。指定された鍵を使用してメッセージダイジェストを再計算し、受信メッセージのダイジェストと比較します。

begin decrypt procedure
if (peer.authenable = 0) begin /* 認証無効 */
peer.authentic <- 1;
exit;
endif

/* 鍵識別子が有効かどうかを確認 */
if (pkt.keyid not in sys.keys) begin
peer.authentic <- 0;
exit;
endif

/* 受信したダイジェストを抽出 */
received_digest <- pkt.check;

/* 期待されるダイジェストを計算 */
expected_digest <- MD5(message || key[pkt.keyid]);

/* ダイジェストを比較 */
if (received_digest = expected_digest)
peer.authentic <- 1;
else
peer.authentic <- 0;

end decrypt procedure

認証が成功した場合(ダイジェストが一致)、認証ビット(peer.authentic)は1に設定され、メッセージが正当なピアから発信されたことを示します。認証が失敗した場合、ビットは0に設定され、構成に応じてメッセージが拒否される場合があります。

C.2.3. 制御メッセージ手順

付録Bで説明されているNTP制御メッセージが認証付きで実装されている場合、同じ認証メカニズムが使用されます。暗号化および復号化手順は、通常のNTPメッセージと同じ方法で適用されます。

制御メッセージの場合、これらのメッセージはNTP実装の内部変数を読み取りおよび変更するために使用できるため、認証が特に重要です。認証なしでは、攻撃者が時間同期を妨害したり、機密情報を抽出したりする可能性があります。

実装上の考慮事項

認証メカニズムを実装する際には、以下の考慮事項を考慮する必要があります:

  1. 鍵管理: 認証を使用するすべてのピアで共有秘密鍵を手動で構成する必要があります。セキュリティを維持するために、鍵は定期的に変更する必要があります。

  2. パフォーマンスへの影響: MD5ダイジェストの計算は、各メッセージに処理オーバーヘッドを追加します。CPUリソースが限られているシステムでは、これがタイミング精度に影響を与える可能性があります。実装は、ダイジェスト計算のキャッシングや利用可能な場合のハードウェアアクセラレーションの使用を検討する必要があります。

  3. タイムスタンプ精度: 暗号化操作は、タイムスタンプ精度への影響を最小限に抑えるために、実際のメッセージ送信にできるだけ近い場所で実行する必要があります。一部の実装では、暗号化遅延を補償するためにダイジェストオフセットを事前計算します。

  4. 鍵識別子空間: 32ビットの鍵識別子空間により、多数の鍵が可能になり、鍵のローテーションが容易になり、複数の認証ドメインをサポートできます。

  5. 下位互換性: 認証ありとなしのメッセージは共存できます。認証をサポートしないピアは、認証子フィールドを単に無視します。

  6. セキュリティの制限: 認証メカニズムは、メッセージの変更やリプレイ攻撃から保護しますが、メッセージ内容の暗号化は提供しません。時刻情報自体は平文で送信されます。

ここで説明する認証メカニズムは、ほとんどのNTP展開においてセキュリティとパフォーマンスの間の実用的なバランスを提供します。より強力なセキュリティ保証を必要とする環境では、IPsecやその他のトランスポート層セキュリティメカニズムなどの追加措置が適切な場合があります。