コンテンツにスキップ
getnextpdf.com

デジタル署名は誰が署名したかをどう証明するか

Spec: RFC 5652Spec: RFC 5280, §6Spec: RFC 3161, §1

デジタル署名は三つのことを行います。そして最初からそれらを切り分けておく価値があります。すなわち、バイトが変更されていないことを証明し、誰が署名したかを証明し、そして — 少しの助けを借りて — いつかを証明します。このページはその考えをゼロから組み立てるので、暗号がブラックボックスでなくなります。

「署名済み」は、人々が判断を賭ける言葉です。契約、請求書、誰かが実行するソフトウェアのリリースノート。あるツールが緑色のチェックマークを表示したことしか分からないなら、実際には何が証明されたのかが分かっていません。バイトが無傷だという証明はあっても、誰の鍵が署名したのかは見当もつかない、ということがありえます。本物の署名者はいても、証明書が何年も前に失効している、ということもありえます。各部分を理解することこそが、有効な署名が何を意味するかを — そして同じくらい有用なことに、何を意味しないかを — 正確に言えるようにするものです。

留め金に個人の印章を押し込んだ、改ざんが分かる封筒を思い浮かべてください。

  • 印章は一人の人物に固有で、事実上偽造不可能です。誰もがそれを認識できますが、作れるのはその所有者だけです。それが鍵ペアです。あなただけが持つ秘密鍵と、誰もが見られる公開鍵です。
  • 印章をドキュメント全体の上に押すわけではありません。その小さく偽造不可能な要約 — ハッシュ — の上に押します。ドキュメントの 1 バイトを変えると要約は完全に変わるので、印章はもはや合わなくなります。
  • 署名とは、自分の秘密鍵でドキュメントに対する署名を生成することです — RSA と ECDSA ではハッシュに対して、内部で自らハッシュ化を行う EdDSA ではコンテンツそのものに対して。検証とは、公開鍵、署名、そして同じコンテンツ(ハッシュとして、または直接)を使ってアルゴリズムの確認を実行することです — それは有効か無効かを返します。両者を結びつけるのは信頼ではなく数学です。
  • 証明書は、これが誰の印章かを告げる部分です。それがなければ、ある鍵がバイトに署名したことは証明できても、その鍵が特定の誰かに属することは証明できません。
  • タイムスタンプは、いつかを告げる部分です。署名者自身の時計は単なる主張にすぎず、信頼できる時刻は外部の権威から来ます。

ハッシュから始めましょう。なぜなら、他のすべてがその上に立つからです。暗号学的ハッシュ関数は、任意の量のデータを読み、短く固定長の指紋を生成します — PDF 署名では、典型的には 256 ビットの値です。二つの性質がそれを有用にします。同じ入力は常に同じ指紋を生み、そして同じ指紋を持つ別の入力を見つけることは実行不可能だ、ということです。だからハッシュは、ドキュメントの忠実な代理です。二つのハッシュが一致するなら、バイトは一致します。

次に鍵ペアです。秘密鍵と公開鍵は数学的に結びついていますが、現実的な時間の内に一方から他方を導くことはできません。有効な署名を生成できるのは秘密鍵だけであり、それを確認できるのは対応する公開鍵だけです。署名はその非対称性を使います。署名者は、選んだアルゴリズムが定義する入力 — RSA と ECDSA ではコンテンツのハッシュ、内部でハッシュ化する EdDSA ではコンテンツそのもの — に秘密鍵の操作を適用します。その結果が署名値です。秘密鍵の保持者だけがそれを生成でき、しかもそれがこのコンテンツに結びついているため、二つのことを同時に証明します — 保持者が署名したこと、そしてバイトがそれ以来動いていないことです。

検証はその論理を鏡映します。検証者は同じ入力を再構成します — RSA と ECDSA ではドキュメントをハッシュ化し、EdDSA ではコンテンツを直接取り — それから公開鍵、署名値、そしてその入力に対して署名アルゴリズムの検証操作を実行します。操作は有効か無効かを返します — そしてこれは、アルゴリズムが RSA でも ECDSA でも EdDSA でも同じ形であり、文字どおりハッシュを「復元する」と描けるのが RSA だけであってもそうです。有効は無傷で本物だという意味です。無効は、何かが変わったか、誤った鍵が使われたという意味であり、正直な答えは無効です。

  1. Prepare the inputRSA and ECDSA hash the document to a short, fixed-length fingerprint; EdDSA signs the content directly and hashes it internally. Either way, any change to the bytes changes what is signed.
  2. Sign with the private keyThe signer applies a private-key operation to that input — the hash for RSA and ECDSA, the content for EdDSA. The output is the signature value; only the private-key holder could have produced it.
  3. Reconstruct the inputThe verifier independently rebuilds the same input from the content — a recomputed hash for RSA and ECDSA, the content itself for EdDSA. This is what the verify operation checks against.
  4. Verify with the public keyThe verifier runs the algorithm's verify operation on the public key, the signature value, and that input. The same shape works for RSA, ECDSA, and EdDSA.
  5. Accept or rejectThe verify operation returns valid or invalid. Valid means the bytes are intact and the private-key holder signed them. Otherwise the result is invalid — no guessing.
デジタル署名が第一原理からどう生成され、その後どう確認されるか。署名者は秘密鍵でコンテンツに対する署名を生成します — RSA と ECDSA ではハッシュに対して、EdDSA ではコンテンツそのものに対して。検証者は同じ入力を再構成し、それから公開鍵、署名、その入力に対してアルゴリズムの検証操作を実行します。有効な結果は、バイトが無傷であり、秘密鍵の保持者が署名したことを証明します。

実際の PDF では、NextPDF は印章を可視のページの上に押すのではありません — 宣言されたバイト範囲の上に押し、署名を分離型の CMS オブジェクト(Spec: RFC 5652)としてファイルの内側(Spec: ISO 32000-2, §12.8)に格納します。一つの細かな点が重要です。署名者は生のコンテンツハッシュに直接署名するのではありません。コンテンツのハッシュを含む小さな署名済み属性の集合に署名するので、時刻、コンテンツタイプ、署名者の証明書識別子が、すべて一緒に封印されます。それらのバイトがどこに存在し、なぜ範囲がそのような形になっているかは、署名は PDF の中にどう収まるかの主題です。

ここまでで、数学はある鍵これらのバイトに署名したことを証明します。それが誰の鍵かについては何も語りません。その隙間こそ、証明書が埋めるものです。証明書はそれ自体が — 認証局からの — 署名された言明であり、この公開鍵がこの名前の付いた主体に属することを述べます。それを信頼するとは、署名者の証明書から、信頼すると決めた権威まで連鎖をたどり、その途上で各リンクの有効性を確認することを意味します(Spec: RFC 5280, §6)。その連鎖がなければ、「署名済み」は匿名です。それがあれば、「署名済み」には名前が伴います。

最後の部分はいつです。署名は署名者自身が主張する時刻を埋め込めますが、自分が制御しない時計は、証明ではなく主張です。タイムスタンプ局からのタイムスタンプは、署名のハッシュをある瞬間に結びつけ、ドキュメントに利害を持たない当事者によって証されます(Spec: RFC 3161, §1)。それこそが、署名者の証明書が失効した後も署名が意味を保ち続けられる理由です。証明書がまだ有効だった間に署名が存在したことを示せるのです。より踏み込んだ扱いはタイムスタンプと信頼できる時刻にあります。

以下の形は、平易に書かれた概念上の操作です。眼目は API 呼び出しではなく — 署名検証が鏡像であること、そして改ざんされた 1 バイトが構造上一致を壊すことを見て取ることです。

<?php
declare(strict_types=1);
// SIGN — the holder of the private key seals the content.
// RSA and ECDSA sign a hash; EdDSA signs the content directly (hashing inside).
$signingInput = sign_input($content); // a digest for RSA/ECDSA, the content for EdDSA
$signatureValue = private_key_transform( // only the key holder can do this
privateKey: $signerPrivateKey,
input: $signingInput,
);
// VERIFY — anyone with the public key runs the algorithm's check.
$recomputedInput = sign_input($content); // verifier rebuilds the same input
$intactAndAuthentic = signature_verify( // RSA, ECDSA, EdDSA — same shape
publicKey: $signerPublicKey, // taken from the certificate
signatureValue: $signatureValue,
input: $recomputedInput, // the freshly reconstructed input
);
// true -> bytes unchanged AND signed by the private-key holder
// false -> a byte changed, or the wrong key — the honest answer is "invalid"
// The certificate answers a SEPARATE question: whose public key is this?
// The timestamp answers ANOTHER: when did this signature exist?
// "intact + authentic" alone proves neither identity nor time.

それでも検証を通る変更を偽造することは、計算上実行不可能です。ハッシュはコンテンツを忠実に運ぶため、コンテンツを変えるとハッシュが変わり、検証操作はそれを拒否します — 選んだ関数が非現実的にするよう設計されているハッシュ衝突を見つけない限り。

よくある間違いは、「有効な署名」を「信頼できるドキュメント」と読むことです。それらは同じ文ではありません。暗号が証明するのは、バイトが無傷であること秘密鍵の保持者が署名したことです — それ以上ではありません。聞いたこともない鍵で署名され、認識する権威の誰によっても証されていないドキュメントは、申し分なく「有効」でありながら、何の価値もないことがありえます。同一性は証明書とその連鎖から来ます。時刻は信頼できるタイムスタンプから来ます。これらすべてを静かに一つのブール値に畳み込む緑色のチェックマークは、どの問いが重要だったかを、あなたに代わって決めてしまっています。各部分を知ることこそが、残りを問えるようにするものです。

このページはデジタル署名の考え方を説明するもので、完全な検証手続きではありません。ここでの数学は、完全性と真正性を証明します。それ単独では、署名証明書があなたの思う相手に発行されたのか、署名時点で有効だったのか、あるいはその後に失効したのかは告げません — それらは証明書パスと失効の問いであり、正しい検証はそのすべてを実行します。完全なチェック集合は署名を正しく検証するにあります。

NextPDF は署名構造を構築し、暗号上のチェックを実行します。あなたのトラストアンカーを選ぶことも、いかなる認証局を保証することも、署名の法的効果を決めることもしません — それらは、あなたのデプロイ、証明書、そして法域に依存します。エンジンはその仕組みを証明します。その上に乗る信頼の判断は、あなたのものです。

エンジンが同梱するものは、ティアごとに、この土台から外側へと積み上がります。

Digital signature: integrity, identity, and trusted time — edition availability
EditionAvailability
Core

PAdES B-B: ここで説明したハッシュアンドサインの仕組みを、分離型の CMS SignedData オブジェクトとしてパッケージ化したもの。加えて、あなたが供給するトラストアンカーに対する証明書パス検証。

Pro

PAdES B-T を追加します — 署名値に対する検証済みの RFC 3161 信頼できるタイムスタンプ。これにより「いつ」が、自己申告ではなく証されます。

Enterprise

長期プロファイル(B-LTB-LTA)を追加します。埋め込まれた検証材料とドキュメントタイムスタンプにより、同一性と時刻の証明が、何年にもわたって答えられる状態に保たれます。

  • ハッシュ(ダイジェスト) — 暗号学的ハッシュ関数による、データの短く固定長の指紋。データへのいかなる変更も、それを完全に変える。
  • 鍵ペア — 結びついた秘密鍵(署名者だけが保持)と公開鍵 (自由に共有される)。署名できるのは秘密鍵だけで、検証できるのは対応する公開鍵だけ。
  • 署名 — アルゴリズムが定義する入力 — RSA と ECDSA ではコンテンツのハッシュ、 内部でハッシュ化する EdDSA ではコンテンツそのもの — に秘密鍵の操作を適用すること。 PDF では、そのコンテンツは、ドキュメントのハッシュを含む署名済み属性。結果が署名値。
  • 検証 — 同じ入力(再計算したハッシュ、または EdDSA ではコンテンツそのもの)を再構成し、それから公開鍵、署名値、その入力に対してアルゴリズムの検証操作を実行して、 有効か無効かの答えを得ること。
  • 署名値 — 秘密鍵の操作が生成するバイト。検証者が、新たに再構成したアルゴリズム入力(RSA と ECDSA ではダイジェスト、EdDSA ではコンテンツそのもの)に照らして確認するもの。
  • 証明書 — 公開鍵を名前の付いた同一性に結びつける、署名された言明。受け入れた権威まで連鎖することで信頼される(RFC 5280 §6)。
  • トラストアンカー — 信頼すると決めた認証局。受け入れ可能な証明書連鎖の根。
  • タイムスタンプ(RFC 3161 — タイムスタンプ局からの署名されたトークン。 ハッシュを時刻の値に結びつけ、いつかの信頼できる証明を提供する。
  • CMS SignedData — 署名値と署名者の証明書を運ぶ Cryptographic Message Syntax(RFC 5652)構造。
  • PAdES — PDF Advanced Electronic Signatures。PDF 署名のための ETSI プロファイルファミリ。署名のページで詳しく扱う。