前章の検証は、何を言っていなかったか

第5章の判定は3値でした。valid / drifted / invalid。そこで valid が意味していたのは、正確には次のことだけです。

この証明書が名指した DID の鍵で、署名が検証できた。

「その DID を信じてよいか」は、一言も言っていません。

これは穴になります。攻撃者が自分の鍵で他人の資料に署名すれば、判定は堂々と valid になるからです。しかも did:key はホストも認証局も要らないので、誰でも1秒で「発行者」になれます

第3章で「did:key はその鍵が誰のものか誰も保証しない」と書きました。それが検証の出力にどう現れるか、というのがこの章です。

名簿を1枚置く

対策は、技術的にはあっけないものです。受け入れてよい署名者の名簿を配ります。

{
  "id": "https://nakamura196.github.io/did-log/trustlist.json",
  "name": "Example trust list for cultural heritage issuers",
  "maintainer": "(この試作では未定。名簿を誰が維持するかは技術では決まらない)",
  "entries": [
    {
      "did": "did:web:nakamura196.github.io:did-log",
      "name": "例示大学",
      "notBefore": "2026-01-01T00:00:00Z",
      "scope": ["https://nakamura196.github.io/did-log/iiif/genji/"]
    },
    {
      "did": "did:key:zDnaerjYMognqPq2rcFG8HwbxHEdKWUjfHuNM6Tmb7ZwhN83K",
      "name": "例示県立文書館",
      "notBefore": "2019-04-01T00:00:00Z",
      "notAfter": "2026-06-30T00:00:00Z",
      "scope": ["https://nakamura196.github.io/did-log/iiif/genji/"]
    },
    {
      "did": "did:key:zDnaeqxhJ1Kdk6gEWeWRL7ZQsNvbi5wzMyhVopJNFHGq67ucM",
      "name": "例示美術館",
      "notBefore": "2020-04-01T00:00:00Z",
      "scope": ["https://nakamura196.github.io/did-log/iiif/ise/"]
    }
  ]
}

1件は「いつからいつまで、どの範囲について、この DID の主張を受け入れるか」を表します。これも静的ファイル1枚で配れます。

そして判定に4つ目が加わります。

判定意味
valid署名が通り、署名者が名簿にあり、内容も一致
drifted署名も署名者も通るが、別の版
untrusted署名は数学的に正しいが、署名者を信じる根拠がない
invalid署名が通らない / 期限切れ / 失効 / 別の資料

4つ目は、前の3つとは性質が違います

valid / drifted / invalid が「この文書はどうか」を言うのに対して、 untrusted は「この署名者はどうか」を言う。 前者は手元の計算だけで決まるが、後者は名簿を誰が維持するかという制度に依存する。

名簿を渡さなければこの判定は行われず、従来どおりの3値に戻ります。

5つのケース

ケース内容名簿なし名簿あり
A所蔵機関が署名するvalidvalid
B第三者が他人の資料に署名するvaliduntrusted
C名簿から外れた機関の、外れる前の保証validvalid
D同じ機関が、外れた後に署名するvaliduntrusted
E別の機関が他館の資料に署名するvaliduntrusted

B が要点

[B] 第三者が他人の資料に署名する — did:key。ホストも CA も要らない
  ✔ 発行者の署名  did:key:zDnaeRCfNb5w1Bzn9UFhgB8g6E8tkr27ipEiEGXaDTE35Ln9U の鍵で検証OK
  ✔ 有効期限  (無期限)
  ✔ 失効リスト  該当なし
  ✔ 対象 URI の一致  https://…/iiif/genji/manifest.json
  ✔ 正規化方式の一致  sorted-keys-json
  ✘ 署名者の信用  名簿にない
  名簿なし → valid    名簿あり → untrusted

上の5行がすべて ✔ であることに注目してください。 署名は数学的に完璧で、対象の URI も合っていて、正規化方式も一致しています。第5章までの検証は、これを valid と判定していました。

止めているのは暗号ではありません。名簿です。そして名簿は技術ではありません。

C と D の差 — 判定の基準時刻

同じ機関の、同じ形式の署名でも、結果が分かれます。

[C] 名簿から外れた機関の、外れる前の保証 — 2026-05-01 発行 / 名簿は 06-30 まで
  ✔ 署名者の信用  名簿にある — 例示県立文書館
  ✔  (注記)  発行時点では名簿にあったが、現在は外れている
  名簿あり → valid

[D] 同じ機関が、外れた後に署名する — 2026-08-01 発行
  ✘ 署名者の信用  名簿の有効期間外 — 2026-06-30 に名簿から外れている
  名簿あり → untrusted

判定を「いま」で行うか「発行時点」で行うかの違いです。

「いま」で判定すると、機関が統廃合された瞬間に、それまで出した保証が全部無効になります。長期保存を前提にする以上、これは採れません。だから発行時点で判定します。

代償があります。名簿から外す操作は遡及しません。 不正が後から分かっても、過去に出された保証は取り消せない。取り消したければ、失効リストという別の仕組みが要ります。名簿と失効リストが別々に必要なのは、この非対称性のためです。

E — 名簿にあるだけでは足りない

[E] 別の機関が他館の資料に署名する — 名簿にはあるが、範囲が自館のみ
  ✘ 署名者の信用  名簿の範囲外 —
     例示美術館 は https://…/iiif/genji/manifest.json について語る権限を持たない
  名簿あり → untrusted

名簿に載っていることと、何について語れるかは別です。A館が名簿にいるからといって、B館の資料の真正性を保証してよいことにはなりません。

この試作では名簿の各エントリに scope を持たせて、対象の範囲を書けるようにしました。

C2PA と ARCHANGEL が置いた場所

この穴は、この試作に固有のものではありません。

C2PA(Content Credentials、画像や動画の来歴を記録する規格)が同じ場所に置いたのは C2PA Trust List です。署名者に証明書を出す認証局をリストで配り、そこに繋がらない署名者は信用しない。中身は技術ではなく名簿です。

ただし C2PA の Trust List は認証局を載せるだけで、そこに「何について語れるか」は書かれていません。範囲にあたるものは別の名簿——Conforming Products List——の側にあり、たとえば「この製品は『カメラで撮影した』と主張してはならない」(disallowedSignals)が製品単位で書かれています。証明書の拡張鍵用途(EKU)でも用途は絞られます。

つまり C2PA に範囲の概念が無いのではありません。範囲が署名者名簿とは別の場所に分かれて置かれていて、検証者がそれを参照するかは仕様上 SHOULD 止まり、という形です。上の E に相当する区別は、名簿1枚を見ただけでは付きません。

逆に言えば、所蔵という制度は「誰が何を持っているか」が比較的はっきりしている世界なので、範囲を署名者名簿と同じ1枚に書き下せます。ここは文化資源の側が持っている、珍しく有利な条件です。

ARCHANGEL(英国国立公文書館とサリー大学ほか、2017–19)は、複数の国立公文書館が参加する permissioned chain(proof-of-authority)を使いました。各館が sealer node を運用して合意を取る形です。「permissioned」とは、参加者を事前に決めておく、という意味です。つまり 「どの公文書館を validator にするか」という名簿の問題が、チェーンの内側に入っているだけです。

これは「トラストアンカー」と呼ばれているもの

この名簿にあたるものは、一般に trust anchor(トラストアンカー) と呼ばれます。「信頼の起点」という意味で、そこから先は検証で辿れるが、そこ自体は検証できない点を指します。証明書の連鎖をどこまで遡っても、最後は「これは信じることにする」という一点に行き着きます。名簿は、その一点を明示的に書き出したものです。

実際の枠組みが誰を起点に置いているかを並べます。技術ではなく制度の話なので、枠組みごとにかなり違います。

Gaia-X

欧州のデータ基盤の枠組みです。トラストアンカーの一覧は Gaia-X Registry に置かれ、Gaia-X 側が維持します。

名簿を維持するのはGaia-X(どの種別を受け入れるかは Compliance Document で決め、実際の事業者一覧は Registry に置く)
載っているのはeIDAS の適格トラストサービス事業者(QTSP) ほか、認められた種別の事業者
何を保証するかその事業者が発行した証明書は、参加者の身元確認を経ている

eIDAS を起点にしているのが要点です。欧州には、加盟国政府が維持する信頼リストという制度が先にあり、Gaia-X はそれを借りています。第11章で「EU は既存の公開鍵基盤の上に組んでいる」と書くのは、この構造を指しています。

Pontus-X

Gaia-X 準拠のデータスペースの1つです。ここでは deltaDAO がトラストアンカーとして参加者を受け入れます。

名簿を維持するのはdeltaDAO
載っているのは参加者クレデンシャルを発行された法人
載ると何ができるかサービスの公開・利用、フェデレーションサービスの利用

未登録のアカウントは、そもそも動かすための通貨を受け取れません。 Faucet は「既知のアカウント」にしか配らないので、支払手段が手に入らず、計算資源の利用にも到達しません。加えてサービスの公開者は、消費者を絞る許可・拒否リストを個別に設定できます(既定では誰でも消費できる、と公式ドキュメントは書いています)。つまり名簿は表示上の飾りではなく、実行の可否を実質的に決めています。

3つを並べる

名簿を維持するのは載っているのは
Gaia-XGaia-X(Registry)eIDAS QTSP 等の事業者
Pontus-XdeltaDAO参加者クレデンシャルを持つ法人
C2PAC2PA(Trust List / Conforming Products List)+各検証実装の設定署名者に証明書を出す認証局(範囲は別名簿の側)
この試作未定例示大学 / 例示県立文書館 / 例示美術館

技術的にはどれも「名簿を1つ配る」だけです。 違うのは、その名簿を誰が持つかという一点で、そこが枠組みの性格をほぼ決めています。Gaia-X は政府の制度に寄りかかり、Pontus-X は特定の法人に集約し、C2PA は自前の名簿を持ちつつ参照するかを実装に委ねています。

そして文化資源の分野には、これに相当する主体がまだいません。

この試作が答えを出せない部分

docs/trustlist.jsonmaintainer 欄は空のままです。

誰が名簿を維持し、誰を入れ、誰を外すか。

これは技術では解けません。第4章で「チェーンが witness を務める」と書きましたが、チェーンを持ち込んでもこの問題だけは外れません。ARCHANGEL が permissioned chain で直面したのも、まったく同じものでした。

前節で見た Gaia-X も Pontus-X も、この問いに技術で答えてはいません。誰かが引き受けているだけです。第11章で「EU は既存の公開鍵基盤の上に組んでいる」と書きますが、その「既存」の中身は、暗号ではなくこの名簿を誰が維持するかという合意です。

前章の記述を訂正しておく

第5章では判定を3値と書きましたが、名簿を導入した時点で4値になります。そして valid の意味も変わります。

第5章の validこの章以降の valid
署名が正しい
内容が署名時と一致
署名者を信じる根拠がある

第5章の valid は「この文書は改竄されていない」しか言っていませんでした。誰が保証しているのかは、そこには入っていなかったわけです。