3. Log Format and Operation (ログ形式と動作)
3. Log Format and Operation (ログ形式と動作)
誰でも証明書を証明書ログに公開監査のために提出できます。ただし TLS クライアントはログ済みでない証明書を受理しないため, 通常は証明書所有者またはその CA が提出すると期待されます。ログは, そのような証明書の単一の, 常に成長する追記のみメルクル木です。
有効な証明書がログに提出されると, ログは直ちに Signed Certificate Timestamp (署名付き証明書タイムスタンプ, SCT) を返さなければなりません。SCT は, Maximum Merge Delay (最大マージ遅延, MMD) と呼ばれる固定時間内に証明書をメルクル木に取り込むというログの約束です。ログが以前その証明書を見たことがあれば, 以前返したのと同じ SCT を返してもよいです。TLS サーバは証明書とともに TLS クライアントに1つ以上のログからの SCT を提示しなければなりません。TLS クライアントは, エンドエンティティ証明書に対して有効な SCT がない証明書を拒否しなければなりません。
各ログは定期的に新規エントリをすべてメルクル木に追加し, 木の根に署名します。監査者は, SCT が発行された各証明書が実際にログに現れることを検証できます。ログは SCT 発行から Maximum Merge Delay 期間以内に証明書をメルクル木に取り込まなければなりません。
ログ運用者は, ログからのデータの取得や共有にいかなる条件も課してはなりません。
3.1. Log Entries (ログエントリ)
誰でも任意のログに証明書を提出できます。ログ済みの各証明書を発行者に帰属させるため, ログは受理可能なルート証明書のリストを公開しなければなりません (このリストは主要ブラウザベンダが信頼するルート証明書の和集合であると便利でしょう)。提出される各証明書には, 受理されたルート証明書まで検証するのに必要な追加証明書がすべて付随しなければなりません。ルート証明書自体はログサーバへの提出チェーンから省略してもよいです。
代替として, (ルートおよび中間の) 認証局は発行前に証明書をログに提出してもよいです。そのためには, CA は Precertificate (プリ証明書) を提出し, ログは発行済み証明書に対して有効なエントリを作成するためにこれを用います。Precertificate は, 発行予定の証明書から, エンドエンティティ TBSCertificate の末尾に特別な critical な poison 拡張 (OID 1.3.6.1.4.1.11129.2.4.3, その extnValue OCTET STRING は ASN.1 NULL データ (0x05 0x00) を含む) を付加して構成されます (この拡張は Precertificate が標準の X.509v3 クライアントで検証できないようにするためです)。得られた TBSCertificate は次のいずれかで署名します [RFC5280]。
-
特別目的の (CA:true, Extended Key Usage: Certificate Transparency, OID
1.3.6.1.4.1.11129.2.4.4) Precertificate Signing Certificate。Precertificate Signing Certificate は, 最終的にエンドエンティティ TBSCertificate に署名してエンドエンティティ証明書を得る (ルートまたは中間の) CA 証明書によって直接認証されていなければなりません (発行される証明書が有効であれば, ログはこれを許可するよう標準の検証規則を緩めてもよいことに注意), -
または, 最終証明書に署名する CA 証明書。
上記と同様, Precertificate の提出には, 使用する場合は Precertificate Signing Certificate と, 受理されたルートまでチェーンを検証するのに必要な追加証明書がすべて付随しなければなりません。TBSCertificate 上の署名は, 証明書を発行するという CA の意思を示します。この意思は拘束力があるとみなされます (すなわち, Precertificate の誤発行は最終証明書の誤発行と同等です)。各ログは Precertificate の署名チェーンを検証し, 対応する TBSCertificate に Signed Certificate Timestamp を発行します。
ログは, 提出者が提供した中間 CA 証明書のチェーンを用いて, 提出されたエンドエンティティ証明書または Precertificate が信頼できるルート CA 証明書に遡る有効な署名チェーンを持つことを検証しなければなりません。ログは, 期限切れ, 未発効, 失効済み, または X.509 検証規則上完全には有効でない証明書を, CA の証明書発行ソフトウェアの癖に対応するために受理してもよいです。ただしログは, 既知のルート CA への有効なチェーンのない証明書の公開を拒否しなければなりません。証明書が受理され SCT が発行された場合, 受理ログは検証に用いたチェーン全体 (証明書または Precertificate 自体およびチェーン検証に用いたルート証明書を含み, 提出から省略されていても) を保存し, 要求に応じて監査のためにこのチェーンを提示しなければなりません。このチェーンは, CA が部分的または空のチェーンをログすることで責任を逃れないようにするために必要です (注: これは実質的に, そのような証明書のスパムを抑止する何らかの仕組みが見つかるまで自己署名および DANE ベースの証明書を除外します。著者らは提案を歓迎します)。
ログ内の各証明書エントリには次のコンポーネントが含まれていなければなりません。
enum { x509_entry(0), precert_entry(1), (65535) } LogEntryType;
struct {
LogEntryType entry_type;
select (entry_type) {
case x509_entry: X509ChainEntry;
case precert_entry: PrecertChainEntry;
} entry;
} LogEntry;
opaque ASN.1Cert<1..2^24-1>;
struct {
ASN.1Cert leaf_certificate;
ASN.1Cert certificate_chain<0..2^24-1>;
} X509ChainEntry;
struct {
ASN.1Cert pre_certificate;
ASN.1Cert precertificate_chain<0..2^24-1>;
} PrecertChainEntry;
ログは受理するチェーンの長さを制限してもよいです。
entry_type はこのエントリの型です。本プロトコルバージョンの将来改訂で新しい LogEntryType 値が追加される場合があります。未知のエントリ型をクライアントがどう扱うかは第4節で説明します。
leaf_certificate は監査のために提出されたエンドエンティティ証明書です。
certificate_chain はエンドエンティティ証明書を検証するのに必要な追加証明書のチェーンです。最初の証明書はエンドエンティティ証明書を認証しなければなりません。続く各証明書は直前の証明書を直接認証しなければなりません。最終証明書はログが受理するルート証明書でなければなりません。
pre_certificate は監査のために提出された Precertificate です。
precertificate_chain は Precertificate 提出を検証するのに必要な追加証明書のチェーンです。最初の証明書は有効な Precertificate Signing Certificate であってもよく, 提出された Precertificate (pre_certificate) を認証しなければなりません。続く各証明書は直前の証明書を直接認証しなければなりません。最終証明書はログが受理するルート証明書でなければなりません。
3.2. Structure of the Signed Certificate Timestamp (署名付き証明書タイムスタンプの構造)
enum { certificate_timestamp(0), tree_hash(1), (255) }
SignatureType;
enum { v1(0), (255) }
Version;
struct {
opaque key_id[32];
} LogID;
opaque TBSCertificate<1..2^24-1>;
struct {
opaque issuer_key_hash[32];
TBSCertificate tbs_certificate;
} PreCert;
opaque CtExtensions<0..2^16-1>;
key_id はログの公開鍵の SHA-256 ハッシュであり, SubjectPublicKeyInfo として表される鍵の DER エンコーディング上で計算されます。
issuer_key_hash は証明書発行者の公開鍵の SHA-256 ハッシュであり, SubjectPublicKeyInfo として表される鍵の DER エンコーディング上で計算されます。これは発行者を最終証明書に束縛するために必要です。
tbs_certificate は Precertificate の DER エンコードされた TBSCertificate コンポーネントです。すなわち署名と poison 拡張を除きます。Precertificate が最終証明書を発行する CA 証明書で署名されていない場合, TBSCertificate の発行者 (issuer) も最終証明書を発行する CA のものに変更されています。なお, 最終証明書から TBSCertificate を取り出し SCT 拡張を削除することでこの TBSCertificate を再構成することもできます。また TBSCertificate には Precertificate の署名アルゴリズムおよび最終証明書の署名アルゴリズムの両方と一致しなければならない AlgorithmIdentifier が含まれるため, 同一のアルゴリズムとパラメータで署名されていなければなりません。Precertificate が Precertificate Signing Certificate を用いて発行され, TBSCertificate に Authority Key Identifier 拡張がある場合, 対応する拡張は Precertificate Signing Certificate にも存在しなければなりません。この場合, TBSCertificate の Authority Key Identifier も最終発行者に合わせて変更されています。
struct {
Version sct_version;
LogID id;
uint64 timestamp;
CtExtensions extensions;
digitally-signed struct {
Version sct_version;
SignatureType signature_type = certificate_timestamp;
uint64 timestamp;
LogEntryType entry_type;
select(entry_type) {
case x509_entry: ASN.1Cert;
case precert_entry: PreCert;
} signed_entry;
CtExtensions extensions;
};
} SignedCertificateTimestamp;
digitally-signed 要素のエンコーディングは [RFC5246] で定義されます。
sct_version は SCT が従うプロトコルバージョンです。本バージョンは v1 です。
timestamp は現在の NTP 時刻 [RFC5905] で, 紀元 (1970年1月1日 00:00) からのミリ秒であり, うるう秒は無視します。
entry_type は SCT が提示される文脈から暗黙のうちに分かる場合があります。
signed_entry は上記のとおり, X509ChainEntry の場合は leaf_certificate, PrecertChainEntry の場合は PreCert です。
extensions は本プロトコルバージョン (v1) への将来の拡張です。現在, 拡張は指定されていません。
3.3. Including the Signed Certificate Timestamp in the TLS Handshake (TLSハンドシェイクへの署名付き証明書タイムスタンプの含め方)
少なくとも1つのログに対応するエンドエンティティ証明書の SCT データは TLS ハンドシェイクに含まれていなければなりません。後述の X509v3 証明書拡張, 型 signed_certificate_timestamp の TLS 拡張 ([RFC5246] の第7.4.1.4節), または Online Certificate Status Protocol (OCSP) Stapling (「Certificate Status Request」 TLS 拡張としても知られる, [RFC6066] 参照) のいずれかにより, 応答に OID 1.3.6.1.4.1.11129.2.4.5 の OCSP 拡張 ( [RFC2560] 参照) と本体が含まれる場合:
SignedCertificateTimestampList ::= OCTET STRING
少なくとも1つの SCT が含まれていなければなりません。サーバ運用者は1つより多くの SCT を含めてもよいです。
同様に, 認証局は Precertificate を複数のログに提出してもよく, 得られたすべての SCT は SignedCertificateTimestampList 構造を ASN.1 OCTET STRING としてエンコードし, 得られたデータを OID 1.3.6.1.4.1.11129.2.4.2 の X509v3 証明書拡張として TBSCertificate に挿入することで, 最終証明書に直接埋め込めます。証明書を受け取ったクライアントは, 元の TBSCertificate を再構成して SCT 署名を検証できます。
OCSP 拡張または X509v3 証明書拡張に埋め込まれる ASN.1 OCTET STRING の内容は次のとおりです。
opaque SerializedSCT<1..2^16-1>;
struct {
SerializedSCT sct_list <1..2^16-1>;
} SignedCertificateTimestampList;
ここで SerializedSCT は直列化された TLS 構造を含む不透明なバイト列です。このエンコーディングにより TLS クライアントは各 SCT を個別にデコードできます (すなわち, バージョンアップグレードがあっても, 古いクライアントは理解できない新しいバージョンの SCT をスキップしながら古い SCT を解析できます)。
同様に, SCT は TLS 拡張に埋め込むこともできます。詳細は下記のとおりです。
TLS クライアントは3つの仕組みすべてを実装しなければなりません。サーバは3つのうち少なくとも1つを実装しなければなりません。既存の TLS サーバは一般に, 改変なしに証明書拡張の仕組みを利用できます。
TLS サーバは, 1つ以上のログがクライアントに受け入れられない場合 (例: ログが不正行為で失格になった, 鍵が侵害された) に備え, 複数のログからの SCT を送るべきです。
3.3.1. TLS Extension (TLS拡張)
SCT は型 signed_certificate_timestamp の TLS 拡張を用いて TLS ハンドシェイク中に送れます。
拡張をサポートするクライアントは, 適切な型と空の extension_data を伴う ClientHello 拡張を送るべきです。
サーバは ClientHello で拡張を提示したクライアントに対してのみ SCT を送らなければなりません。その場合, extension_data を SignedCertificateTimestampList に設定して SCT を送ります。
セッション再開では元のセッション情報が使われます。クライアントは ClientHello に拡張型を含めるべきですが, セッションが再開された場合, サーバはそれを処理したり ServerHello に拡張を含めたりすることは期待されません。
3.4. Merkle Tree (メルクル木)
メルクルツリーハッシュのハッシュアルゴリズムは SHA-256 です。
メルクル木入力の構造:
enum { timestamped_entry(0), (255) }
MerkleLeafType;
struct {
uint64 timestamp;
LogEntryType entry_type;
select (entry_type) {
case x509_entry: ASN.1Cert;
case precert_entry: PreCert;
} signed_entry;
CtExtensions extensions;
} TimestampedEntry;
struct {
Version version;
MerkleLeafType leaf_type;
select (leaf_type) {
case timestamped_entry: TimestampedEntry;
}
} MerkleTreeLeaf;
ここで version は MerkleTreeLeaf が対応するプロトコルバージョンです。本バージョンは v1 です。
leaf_type は葉入力の型です。現在定義されているのは SCT に対応する timestamped_entry のみです。本プロトコルバージョンの将来改訂で新しい MerkleLeafType が追加される場合があります。未知の葉型をクライアントがどう扱うかは第4節で説明します。
timestamp はこの証明書に対して発行された対応する SCT のタイムスタンプです。
signed_entry は対応する SCT の signed_entry です。
extensions は対応する SCT の extensions です。
メルクル木の葉は, 対応する MerkleTreeLeaf 構造のリーフハッシュです。
3.5. Signed Tree Head (署名付きツリーヘッド)
ログが木に新規エントリを追加するたびに, ログは対応するツリーハッシュとツリー情報に署名すべきです (対応する Signed Tree Head クライアントメッセージは第4.3節参照)。そのデータの署名は次のように構造化されます。
digitally-signed struct {
Version version;
SignatureType signature_type = tree_hash;
uint64 timestamp;
uint64 tree_size;
opaque sha256_root_hash[32];
} TreeHeadSignature;
version は TreeHeadSignature が従うプロトコルバージョンです。本バージョンは v1 です。
timestamp は現在時刻です。タイムスタンプは木内の最新の SCT タイムスタンプと同じかそれより新しくなければなりません。後続の各タイムスタンプは, 前回の更新のタイムスタンプより新しくなければなりません。
tree_size は新しい木のエントリ数に等しいです。
sha256_root_hash はメルクルハッシュ木の根です。
各ログは要求に応じて Maximum Merge Delay より古くない Signed Tree Head を生成しなければなりません。MMD 期間中に新規提出が全くないというありそうもない事象では, ログは同じメルクルツリーハッシュに新しいタイムスタンプで署名しなければなりません。