コンテンツにスキップ

既存の署名を検査し、信頼境界を理解する

このレシピでは、Core インスペクターを使用して PDF に署名が含まれているかを検出し、その境界を明確にします。署名を検出することは、その署名を検証することではありません。暗号的検証、信頼パス検証、失効確認は、Premium または外部の検証器で行います。

  • Core をインストール済みであること: composer require nextpdf/core:^3
  • 検査対象の PDF ファイル。
  1. PDF のバイト列を読み込みます。
  2. 続いて、Inspector を作成し、inspect() を呼び出します。
  3. 返された InspectResult::$hasSigned を読み取ります。true は、署名辞書がファイル内に存在することを意味します。
  4. 周辺情報を把握するため、InspectResult::$isEncrypted とリスクフラグを読み取ります。
  5. 暗号的な判定を行うために、ファイルを検証器へ渡します。インスペクターが報告するのは存在の有無であり、有効性ではありません。

以下の図は、2 つのことを示しています。1 つはこのレシピが明確にする境界、つまり 存在は有効性ではない という点です。もう 1 つは、実際の検証でなお必要となるチェックの全体像です。

false

true

Yes

No

Yes

No / unknown

Incoming PDF

Inspector.inspect — Quick

hasSigned?

No signature present

Signature dictionary PRESENT

NOT yet validity

Recompute byte-range digest

ISO 32000-2 §12.8.1

Validate CMS SignedData

Build & check X.509 path

to a chosen trust anchor

Check revocation OCSP / CRL

Long-term input?

Read DSS validation material

All checks evaluated

Every check passed?

Trustworthy

Not trusted — do not act

Diagram
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Inspect\Inspector;
use NextPDF\Inspect\InspectConfig;
$pdfData = file_get_contents(__DIR__ . '/incoming.pdf');
if ($pdfData === false || $pdfData === '') {
fwrite(STDERR, "Cannot read incoming.pdf\n");
exit(1);
}
$inspector = new Inspector();
// InspectConfig::quick() selects InspectDepth::Quick. This is the only
// depth that runs offline: a default Inspector has no Spectrum sidecar,
// and without a sidecar Quick is the sole path that returns a result.
// Standard and Full require the sidecar (see the SIDECAR-001 edge case).
$result = $inspector->inspect(
$pdfData,
InspectConfig::quick(),
);
// hasSigned reports the PRESENCE of a signature dictionary.
// It does NOT mean the signature verifies.
if ($result->hasSigned) {
echo "A signature is present in incoming.pdf\n";
echo "Encrypted: " . ($result->isEncrypted ? 'yes' : 'no') . "\n";
echo "Next step: run a cryptographic verifier before trusting it.\n";
} else {
echo "No signature found in incoming.pdf\n";
}

署名済みの入力の場合:

A signature is present in incoming.pdf
Encrypted: no
Next step: run a cryptographic verifier before trusting it.

未署名の入力の場合:

No signature found in incoming.pdf
  • 存在は有効性ではない — 境界。 InspectResult::$hasSigned は、署名辞書がファイル内に存在することを報告します。CMS 構造、バイトレンジダイジェスト、署名証明書、証明書チェーン、失効状態は確認しません。改ざんされたファイルでも、hasSigned = true を報告する場合があります。存在を完全性や作成者の証明として扱ってはなりません。
  • 完全な検証に必要なもの。 完全な判定では、バイトレンジダイジェストを再計算して比較し(ISO 32000-2 §12.8.1)、CMS SignedData を検証し、信頼アンカーへの X.509 パスを構築して確認し、OCSP または CRL で失効を確認します。長期保存用の入力では、検証データは DSS に格納されます(ETSI EN 319 142-2 §6.3.1)。これらの操作は SignerInterface および LtvManagerInterface コントラクトの背後で実行されます。本番実装は Pro エディションおよび Enterprise エディションに同梱されています。もう 1 つのサポートされる経路は、外部のバリデーターです。
  • 検査の深度とサイドカー(SIDECAR-001)。 デフォルトの new Inspector() には、Spectrum サイドカーが構成されていません。サイドカーがない場合、結果を返すのは InspectDepth::Quick のみです。InspectDepth::Quick は、プロセス内の PHP フォールバックを使用します。InspectDepth::StandardInspectDepth::Full は、いずれもサイドカーを必要とします。サイドカーが利用できない場合、これらはコード INSPECT-SIDECAR-001(“Spectrum sidecar is required for Standard/Full depth inspection”、retryable = true)とともに InspectException をスローします。InspectConfig コンストラクターの デフォルトの深度は Standard です。したがって、素の new InspectConfig()(または new InspectConfig(depth: InspectDepth::Standard))は、オフラインで 使用できませんhasSigned を読み取る前に SIDECAR-001 をスローします。オフラインでの存在検出には、このレシピと同様に InspectConfig::quick() を使用します。Core では、いずれの深度でも暗号的な署名検証は行いません。
  • 空の入力。 空文字列は、コード INSPECT-INPUT-001 とともに InspectException をスローします。読み込みをガードしてください。
  • 複数の署名。 存在フラグは、署名の数を数えたり、承認署名と文書タイムスタンプを区別したりしません。署名の数や署名ごとの判定が重要な場合は、専用の検証器を使用してください。
記述仕様箇条リファレンス ID
署名値は、署名辞書の Contents エントリーに格納されます。ISO 32000-2§12.8.1
検証では、署名値を除外して ByteRange 全体にわたってダイジェストを再計算します。ISO 32000-2§12.8.1
長期検証データは DSS に格納されます。ETSI EN 319 142-2§6.3.1

このレシピは、署名の存在を検出します。いずれの署名についても、有効である、信頼されている、または失効していないことを主張するものではありません。その判定は、暗号的な検証器が担います。