Enterprise エディション
eIDAS 保証レベル
NextPDF Enterprise は、EU トラステッドリストの証拠を明示的な eIDAS 保証レベル(LoA)へと変換します。NextPDF\Enterprise\Security\Eidas\LoaMapping サービスは、1 つのトラストサービスエントリを Low、Substantial、または High に分類します。返される LoaAssertion は、レベルに加えて機械可読な理由コードを保持します。ワークフローは保証を基準にゲートを設けることができ(「High を要求する」など)、その理由を監査証拠としてアーカイブできます。付随するガードである CertPiiGuard は、監査レコードがプロセスを離れる前に署名者の識別情報フィールドを秘匿します。
この機能は、2 つの境界によって誠実に枠づけられています。第 1 に、資格認定(qualification)は常に加盟国の監督下にあるトラストサービスプロバイダ(TSP)に帰属します。NextPDF は公開された証拠に対して分類をアサートするのであり、資格を付与、授与、または認証することは決してありません。第 2 に、本ページは LoA アサーションとマッピングのみを扱います。構造的な PAdES ポリシー eidasQualified() は、その合否基準も含めて 検証 に記載されています。
提供とライセンス
「提供とライセンス」という見出しのセクションこの機能は NextPDF Enterprise(nextpdf/enterprise)に含まれ、Enterprise ティアのライセンスエンベロープで有効化されます。その権限を持たないデプロイメントでは、当該機能のクラスはロードされません。エディションを比較してライセンスを取得する。
インストール
「インストール」という見出しのセクションcomposer require nextpdf/enterprisenextpdf/premium メタパッケージも Enterprise パッケージを解決します。有効化には Enterprise ライセンスエンベロープを使用します。ライセンスと有効化 を参照してください。eIDAS クラスは、エンジンのベースライン以上の PHP 拡張を必要としません。これらは NextPDF\Enterprise\Security\Eidas および NextPDF\Enterprise\Signature\Eidas の下でオートロードされます。
概念の概観
「概念の概観」という見出しのセクションRegulation (EU) No 910/2014 (eIDAS) は、3 つの保証レベル、すなわち low、substantial、high を定義しています(Article 8(1))。各レベルは、主張された身元に対する信頼の度合いを表します。レベル high は、身元の悪用や改変を単に軽減するのではなく防止することを目的とした制御を追加します(Article 8(2)(c))。Article 8 は、これらのレベルを電子的識別スキームについて定義しています。NextPDF は同じ語彙を再利用して、署名証明書の背後にあるトラストサービス証拠を分類します。この再利用は、ポリシーゲーティングと監査のためのエンジニアリング上の慣行であり、法的な等価性ではありません。
LoaLevel enum は 3 つのレベルをモデル化します。その backing 値は素のラベルではなく eIDAS LoA URI であるため、永続化されたアサーションは完全な識別子を保持します。rank() は全順序(Low = 1、Substantial = 2、High = 3)を与え、meetsOrExceeds() は要求される下限と比較します。
LoaMapping は、1 つのトラステッドリストエントリ、すなわち Enterprise トラステッドリストサブシステム(NextPDF\Enterprise\Security\Tsl)の TspService からレベルを算出します。このマッピングは決定論的です。
| トラステッドリスト証拠 | レベル | 理由コード |
|---|---|---|
| サービスステータスが granted ではない | Low | service_not_granted |
サービスタイプが CA/QC ではない | Low | service_not_qualified_ca |
QCWithQSCD を伴い QCNoQSCD を伴わない granted な CA/QC | High | ca_qc_with_qscd に加えて esig_or_eseal または qc_default |
それ以外の granted な CA/QC | Substantial | ca_qc_no_qscd_or_unspecified |
QSCD(適格署名生成デバイス)修飾子が要となります。Article 3(12) の下では、適格電子署名には適格証明書と適格生成デバイスの両方が必要です。したがって、証明書が QSCD 上で管理されているというトラステッドリストの記述こそが、High アサーションを支える証拠です。その記述がなければ、granted な適格 CA であっても支えられるのは Substantial であり、High にはなりません。
その結果が LoaAssertion です。レベルに理由コードのリストを加えたものです。理由コードにより、監査の利用者は後から同じ証拠に基づいて分類を再導出できます。下流のポリシー評価器は、そのアサーションを署名検証の結果とともに記録できます。
このモジュールにはもう 1 つの部品が含まれます。CertPiiGuard です。検証成果物が JSON 監査バンドルへシリアライズされる際、署名者証明書は個人データ、すなわち Subject CN、email 属性、そして自然人の国民識別子をエンコードし得る serialNumber 属性を保持します。GDPR Article 5(1)(c) は、処理が必要なものに限定されることを要求します。そのためガードは既定でこれらのフィールドを秘匿し、構造的なエンベロープ(組織、国、チェーンおよびステータスの各フィールド)を保ちながら値を [REDACTED] に置き換えます。利用者は誰が署名したかを知ることなく、署名が合格したかどうかを依然として検証できます。
なぜこの仕組みなのか
「なぜこの仕組みなのか」という見出しのセクション要となる設計判断は、保証アサーションを検証判定から分離することです。署名検証は、ETSI EN 319 102-1 に従い、ステータス表示、すなわち TOTAL-PASSED、TOTAL-FAILED、または INDETERMINATE で終わり、その判定は検証レイヤーに帰属します。LoA マッピングは、素のラベルではなく理由コードを伴う、トラステッドリスト証拠に対する別個で再現可能な分類です。これにより NextPDF は、保証の主張を検証結果として、あるいは検証結果を資格認定の付与として提示することを決してしません。また、この設計はマッピングを構造的に保守的なものにします。証拠が欠落しているか曖昧であれば、レベルは下がるのであって、決して上がりません。
設計の背景: 適格署名の解説。
API サーフェス
「API サーフェス」という見出しのセクション以下のシンボルはすべて nextpdf/enterprise 3.1.0 のパブリック API です。
LoaLevel
「LoaLevel」という見出しのセクションenum LoaLevel: string{ case Low = 'http://eidas.europa.eu/LoA/low'; case Substantial = 'http://eidas.europa.eu/LoA/substantial'; case High = 'http://eidas.europa.eu/LoA/high';
public function rank(): int
public function meetsOrExceeds(self $required): bool}スロー/失敗の条件: rank() および meetsOrExceeds() からは何もありません。LoaLevel::from() によるネイティブ enum の構築は、認識されない URI に対して \ValueError をスローします。LoaLevel::tryFrom() は代わりに null を返します。
LoaMapping
「LoaMapping」という見出しのセクションfinal class LoaMapping{ public function loaForService(TspService $service): LoaAssertion}スロー/失敗の条件: なし。このメソッドは全域的(total)であり、あらゆる TspService 入力が LoaAssertion を生成します。
入力 DTO である NextPDF\Enterprise\Security\Tsl\TspService と NextPDF\Enterprise\Security\Tsl\TspServiceQualifier は、安定したパブリック DTO(@api)です。マッピングは TspService::STATUS_GRANTED、TspService::TYPE_CA_QC、および修飾子定数 TspServiceQualifier::QSCD_STATEMENT(QCWithQSCD)、TspServiceQualifier::NO_QSCD(QCNoQSCD)、TspServiceQualifier::FOR_ESIG、TspServiceQualifier::FOR_ESEAL を参照します。
LoaAssertion
「LoaAssertion」という見出しのセクションfinal readonly class LoaAssertion{ /** * @param list<non-empty-string> $reasons Machine-readable reason codes for the assertion. */ public function __construct( public LoaLevel $level, public array $reasons, ) {}}スロー/失敗の条件: なし。イミュータブルな値オブジェクトです。
CertPiiGuard
「CertPiiGuard」という見出しのセクションfinal readonly class CertPiiGuard{ public function __construct( private bool $disclosePii = false, ) {}
public function disclosesPii(): bool
public function guardSignerCommonName(string $signer): string
public function guardDistinguishedName(string $dn): string
public function guardTsaName(string $tsaName): string
public function guardRootIssuer(string $issuer): string
public function guardChainIssue(string $issue): string}スロー/失敗の条件: なし。ガードは純粋な文字列変換です。確実にトークン化できない DN コンポーネントに対しては、ガードはフェイルクローズし、部分的にマスクした値を出力する代わりに、そのコンポーネントを [REDACTED] へ折り畳みます。
コードサンプル — クイックスタート
「コードサンプル — クイックスタート」という見出しのセクションLoA URI を解析し、要求される下限と比較します。
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Eidas\LoaLevel;
// A LoA URI as persisted in an audit record or received from a peer system.$uri = 'http://eidas.europa.eu/LoA/substantial';
try { $level = LoaLevel::from($uri);} catch (\ValueError $e) { // Unknown URI: refuse to classify. Never guess an assurance level. echo "Unrecognized LoA URI: {$uri}\n"; exit(1);}
echo 'Level: ' . $level->name . ' (rank ' . $level->rank() . ")\n";echo 'Meets substantial: ' . ($level->meetsOrExceeds(LoaLevel::Substantial) ? 'yes' : 'no') . "\n";echo 'Meets high: ' . ($level->meetsOrExceeds(LoaLevel::High) ? 'yes' : 'no') . "\n";想定される出力:
Level: Substantial (rank 2)Meets substantial: yesMeets high: noコードサンプル — 本番
「コードサンプル — 本番」という見出しのセクショントラステッドリストエントリを分類し、要求レベルでゲートし、秘匿された監査レコードを出力します。
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Eidas\LoaLevel;use NextPDF\Enterprise\Security\Eidas\LoaMapping;use NextPDF\Enterprise\Security\Tsl\TspService;use NextPDF\Enterprise\Security\Tsl\TspServiceQualifier;use NextPDF\Enterprise\Signature\Eidas\CertPiiGuard;
// Normally produced by the Enterprise trusted-list subsystem from a// member-state TSL; constructed inline here for a self-contained example.$caPem = (string) file_get_contents(__DIR__ . '/example-qc-ca.pem');
$service = new TspService( tspName: 'Example Qualified TSP', serviceName: 'Example Qualified CA G2', serviceTypeIdentifier: TspService::TYPE_CA_QC, serviceStatus: TspService::STATUS_GRANTED, statusStartingTime: '2024-01-01T00:00:00Z', serviceCertificatePem: $caPem, qualifiers: [ new TspServiceQualifier(qualifierUri: TspServiceQualifier::QSCD_STATEMENT), new TspServiceQualifier(qualifierUri: TspServiceQualifier::FOR_ESIG), ], additionalServiceInformation: [],);
try { // Required floor from deployment configuration; defaults to High. $required = LoaLevel::from(getenv('LOA_REQUIRED') ?: LoaLevel::High->value);} catch (\ValueError $e) { echo "Invalid LOA_REQUIRED URI; refusing to continue.\n"; exit(1);}
$mapping = new LoaMapping();$assertion = $mapping->loaForService($service);
// Privacy by default: signer identity fields are redacted in audit output.$guard = new CertPiiGuard();
$audit = [ 'loa' => $assertion->level->value, 'reasons' => $assertion->reasons, 'meets_required' => $assertion->level->meetsOrExceeds($required), 'signer' => $guard->guardSignerCommonName('CN=Jane Example, O=Example Corp, C=DE'),];
echo json_encode($audit, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";想定される出力:
{ "loa": "http://eidas.europa.eu/LoA/high", "reasons": [ "ca_qc_with_qscd", "esig_or_eseal" ], "meets_required": true, "signer": "CN=[REDACTED], O=Example Corp, C=DE"}エッジケースと落とし穴
「エッジケースと落とし穴」という見出しのセクションLoaLevel::from()は未知の URI に対して\ValueErrorをスローします。nullの扱いが望ましい場合はLoaLevel::tryFrom()を使用してください。- 相反するデバイス証拠は保守的なままです。
QCWithQSCDとQCNoQSCDの両方を持つサービスは、HighではなくSubstantialにマッピングされます。 - 修飾子を持たない granted な
CA/QCサービスは、理由ca_qc_no_qscd_or_unspecifiedを伴ってSubstantialにマッピングされます。既定で適格ですが、デバイスは未証明です。 - 追跡対象セット外の修飾子 URI は分類に影響しません。未知または将来の修飾子がレベルを上げることは決してありません。
- マッピングは現在のサービスステータスのみを読み取ります。
statusStartingTimeの履歴は評価しません。時点指定のウィンドウは検証レイヤーに帰属します。 rank()の整数ではなく、enum の backing URI を永続化してください。ランクは比較のためだけに存在します。CertPiiGuardは=を持たない素の名前を全体として[REDACTED]に折り畳みます。空文字列はすべてのガードを変更されずに通過します。- レガシーな OpenSSL のスラッシュ区切り DN は検出され、構造的にマスクされます。RFC 4514 の値の内部にある
/は、区切り文字ではなく内容として扱われます。 - 個人情報ではない DN 属性(
O、OU、C、ST、L)は保持されるため、管轄に関する推論は秘匿後も残ります。
セキュリティに関する注意
「セキュリティに関する注意」という見出しのセクション- プライバシー・バイ・デフォルト。 ガードのコンストラクタは既定で
disclosePii: falseです。new CertPiiGuard(disclosePii: true)を構築するのは、署名者の識別情報を処理するための文書化された適法な根拠を保有している場合に限ってください。これは、シリアライズ境界において GDPR Article 5(1)(c) のデータ最小化を実装するものです。 - フェイルクローズな秘匿。 DN コンポーネントを確実にトークン化できない場合、そのコンポーネント全体が
[REDACTED]に折り畳まれます。プライバシー制御が決してフェイルオープンすることはありません。 - 決定論的な出力。 ガードは純粋な文字列処理を用います。クロックも乱数もありません。したがってマスクされた出力は、同一入力に対してバイト安定です。安定した出力は監査差分を意味あるものに保ちます。
- 秘匿は暗号化ではありません。
[REDACTED]は値をレコードから取り除きます。識別情報を復元可能にする必要がある場合は、それを独自の適法な根拠とアクセス制御の下で別途保存してください。 - ゴミを入れればゴミが出ます。
LoaAssertionは、その背後にあるトラステッドリスト証拠と同じ程度にしか信頼できません。エントリをマッピングに渡す前に、Enterprise トラステッドリストサブシステムを通じてトラステッドリストを取得し、署名チェックしてください。
NextPDF Enterprise は、Regulation (EU) No 910/2014 Article 8(保証レベル)および Article 3(12)(適格電子署名の要素)、ならびに ETSI のトラステッドリスト修飾子語彙に基づいて情報を得た振る舞いを実装します。サポートは適合ではなく、適合は認証ではありません。NextPDF は認証を保有しておらず、いかなる認証も付与しません。NextPDF は適格トラストサービスプロバイダではなく、適合性評価機関でもなく、監督機関でもありません。LoaAssertion は公開された証拠のソフトウェアによる分類です。それは資格認定または保証の法的判断ではなく、署名を適格にすることもできません。
Regulation (EU) 2024/1183 (eIDAS 2) は、引き続き Article 8 のレベルを参照し、European Digital Identity Wallet が保証レベル high で提供されることを要求します。本ページはこれを規制上の文脈として引用しています。NextPDF はウォレットに関連するいかなる機能主張も行いません。
特定の署名が構造的な eIDAS 志向のポリシーを満たすかどうかは別問題であり、検証モジュールが回答します。検証 を参照してください。
FIPS モードの振る舞い
「FIPS モードの振る舞い」という見出しのセクションeIDAS LoA クラスは暗号操作を一切行いません。ハッシュ化も、署名検証も、乱数生成もありません。Enterprise の FIPS モードポリシーは暗号上の選択をゲートしますが、このモジュールにはゲートすべきものがありません。FIPS モードを有効にしても、LoA マッピングや PII ガードの振る舞いは変わりません。署名とトラステッドリストの暗号的検証は検証モジュールおよびセキュリティモジュールによって統制され、そこでは FIPS モードポリシーが適用されます。
振る舞いの契約
「振る舞いの契約」という見出しのセクションLoaMapping::loaForService()は全域的かつ決定論的です。あらゆるTspServiceがLoaAssertionを生成します。このメソッドは決してスローせず、クロック、ネットワーク、グローバルステートを一切参照しません。- 分類は保守的です。欠落した、未知の、または相反する証拠はレベルを下げます。明示的な granted-
CA/QC-with-QSCD 証拠を除いて、何もレベルを上げません。 - 理由コードは機械可読かつ安定しています:
service_not_granted、service_not_qualified_ca、ca_qc_with_qscd、esig_or_eseal、qc_default、ca_qc_no_qscd_or_unspecified。 - レベルの順序は固定です:
Low<Substantial<High。rank()とmeetsOrExceeds()を通じて公開されます。 CertPiiGuardは既定で秘匿し、トークン化に疑いがあればフェイルクローズします。disclosePii: trueの場合、すべてのガードは入力をそのまま返します。- ガードの出力は、同一入力に対してバイト安定です。
Core フォールバック
「Core フォールバック」という見出しのセクションNextPDF Core は PDF 署名を暗号的に検証し、壊れた証拠に対してフェイルクローズします。Core には EU トラステッドリストモデルも、LoaLevel 語彙も、LoA マッピングも、監査シリアライズ向けの eIDAS レイヤー PII ガードもありません。Core 単体では、自ら維持するトラストデータから保証分類を自身で導出し、監査レコードがプロセスを離れる前に独自の秘匿を適用しなければなりません。
公開範囲の境界
「公開範囲の境界」という見出しのセクション本ページは、外部から観測可能な振る舞いとサポートされるパブリック API サーフェスのみを記載します。内部の名前空間パス、ヘルパークラス、メカニズムの表、ランブックのファイル名、チケットのプレフィックスは対象外です。
- 検証 — 構造的なコンプライアンスポリシー。
eidasQualified()のセマンティクスと合否基準を含みます - 署名検証 — PII ガードがそのレポートを保護する、AdES/PAdES の暗号的検証側
- セキュリティ — 詳細リファレンス — セキュリティモジュールの詳細リファレンス
- 適格署名の解説 — 資格認定と保証に関する Insider エッセイ
- 署名が誰の署名かをどう証明するか — 検証側の信頼に関する Insider エッセイ