ข้ามไปยังเนื้อหา
getnextpdf.com

Enterprise รุ่น

การตรวจสอบลายเซ็นแบบกลุ่ม

NextPDF Enterprise ตรวจสอบลายเซ็นดิจิทัลของเอกสาร PDF จำนวนมากได้ในการเรียกใช้เพียงครั้งเดียว NextPDF\Enterprise\Signature\BatchSignatureValidator::validate() รับรายการเอกสารและคืนค่า BatchValidationReport ทุกลายเซ็นจะผ่านไปป์ไลน์แบบ fail-closed เดียวกัน ได้แก่ การยืนยันตัวตนเชิงวิทยาการเข้ารหัสลับ CMS เหนือช่วงไบต์ที่ลงนาม การตรวจสอบห่วงโซ่ใบรับรองที่ยึดกับ trust anchor และการตรวจสอบการเพิกถอนผ่าน OCSP/CRL รายงานจะให้รายละเอียดในระดับแต่ละเอกสารและแต่ละลายเซ็น — CertChainStatus, RevocationStatus, TimestampStatus — เพื่อให้เครื่องมือด้านการปฏิบัติตามข้อกำหนดสามารถอนุมานผลตัดสินทุกรายการใหม่ได้จากหลักฐานที่บันทึกไว้

แบบจำลองผลตัดสินถูกออกแบบให้เข้มงวดโดยเจตนา ลายเซ็นจะเป็น Valid ก็ต่อเมื่อหลักฐานทั้งหมดได้รับการยืนยันอย่างชัดเจนเท่านั้น หลักฐานการเพิกถอนที่ขาดหายไปจะให้ผลเป็น Indeterminate ไม่ใช่ Valid หน้านี้ครอบคลุมตัวจัดการแบบกลุ่มและชนิดผลลัพธ์ของมัน ส่วนการตรวจสอบ AdES ฝั่งเอกสารเดี่ยวมีการบันทึกไว้ใน การตรวจสอบลายเซ็น การฝังวัสดุสำหรับการตรวจสอบระยะยาวมีการบันทึกไว้ใน การจัดเก็บถาวร

ความสามารถนี้มาพร้อมกับ NextPDF Enterprise (nextpdf/enterprise) และเปิดใช้งานด้วยซองใบอนุญาตระดับ Enterprise การติดตั้งที่ไม่มีสิทธิ์ดังกล่าวจะไม่โหลดคลาสของความสามารถนี้ เปรียบเทียบรุ่นและรับใบอนุญาต

Terminal window
composer require nextpdf/enterprise

เมทาแพ็กเกจ nextpdf/premium ก็จะเรียกใช้แพ็กเกจ Enterprise ให้เช่นกัน การเปิดใช้งานจะใช้ซองใบอนุญาต Enterprise ของคุณ ดูที่ การอนุญาตและการเปิดใช้งาน ชนิดข้อมูลแบบกลุ่มจะโหลดอัตโนมัติภายใต้ NextPDF\Enterprise\Signature ไม่จำเป็นต้องใช้ส่วนขยาย PHP อื่นใดนอกเหนือจากพื้นฐานของเอนจิน

การเรียก validate() เพียงครั้งเดียวจะประมวลผลรายการค่า DocumentSignatureInput แต่ละอินพุตประกอบด้วยตัวระบุเอกสาร ไบต์ PDF ดิบ และ trust anchor ที่เข้ารหัสแบบ PEM ซึ่งเป็นทางเลือก ตัวตรวจสอบจะสกัดพจนานุกรมลายเซ็นของแต่ละเอกสารและดำเนินการสามขั้นตอนต่อหนึ่งลายเซ็น

ขั้นตอนที่ 1 — การยืนยันตัวตนเชิงวิทยาการเข้ารหัสลับ บล็อบ CMS/PKCS#7 แบบแยกจาก /Contents จะถูกตรวจสอบเหนือไบต์ที่ /ByteRange ครอบคลุม ตัวตรวจสอบจะคำนวณไดเจสต์ของเนื้อหาขึ้นใหม่เองและเปรียบเทียบกับแอตทริบิวต์ที่ลงนาม messageDigest โดยไม่เชื่อถือไดเจสต์ที่ผู้สร้างจัดหามาเลย (RFC 5652 §5.6) ค่าลายเซ็นต้องผ่านการตรวจสอบ และใบรับรองสำหรับลงนามต้องผูกกับ CMS หาก /Contents หรือ /ByteRange ขาดหายไปหรือมีรูปแบบผิด CMS ที่แจงไม่ได้ ไดเจสต์ไม่ตรงกัน หรือการตรวจสอบลายเซ็นล้มเหลว ทั้งหมดนี้จะ fail closed ลายเซ็นที่ผ่านการตรวจสอบด้วย SHA-1 จะถือว่าอ่อนแอและไม่ถือเป็นการผ่านแบบเต็มรูปแบบ

ขั้นตอนที่ 2 — การตรวจสอบห่วงโซ่และการยึด trust anchor ห่วงโซ่ของผู้ลงนามที่กู้คืนจาก CMS จะถูกตรวจสอบในฐานะเส้นทางการรับรองที่คาดหวัง trustedCerts ที่คุณจัดหาคืออินพุตของ trust anchor ตามความหมายใน RFC 5280 §6.1.1 กล่าวคือ จุดปลายของห่วงโซ่ต้องตรงกับ anchor ที่จัดหามาด้วยลายนิ้วมือ DER SHA-256 ห่วงโซ่ที่มีโครงสร้างสอดคล้องกันแต่จุดปลายไม่ใช่ anchor ที่กำหนดค่าไว้จะไม่ถูกรายงานว่าเชื่อถือได้ หากไม่มี anchor ที่ใช้งานได้ ระบบจะรายงานเฉพาะผลตัดสินเชิงโครงสร้างเท่านั้น และ CertChainStatus::$trusted จะยังคงเป็น false

ขั้นตอนที่ 3 — การเพิกถอน การเพิกถอนจะทำงานเหนือห่วงโซ่ที่กู้คืนหลังจากการยืนยันตัวตน โดยสะท้อนแบบจำลอง ETSI EN 319 102-1 ที่การตรวจสอบการเพิกถอนตามมาหลังการตรวจสอบเส้นทางสำเร็จ (ข้อ 5.2.6.2) OCSP เป็นวิธีหลัก โดยนับเฉพาะการตอบสนองที่ผ่านการตรวจสอบเชิงวิทยาการเข้ารหัสลับเท่านั้น ว่าเป็น Good หรือ Revoked เส้นทาง CRL เป็นทางเลือกสำรองและยืนยันความสดใหม่ของรายการ เมื่อไม่ได้กำหนดค่าไคลเอนต์ใดเลย สถานะจะเป็น unavailable

ผลตัดสินในระดับแต่ละลายเซ็นคือ SignatureValidationStatus การจัดหมวดหมู่นี้สะท้อนแบบจำลองสถานะของ ETSI EN 319 102-1 (TOTAL-PASSED / TOTAL-FAILED / INDETERMINATE) ในระดับแต่ละลายเซ็น:

หลักฐานผลตัดสิน
ใบรับรองได้รับการยืนยันว่าถูกเพิกถอนInvalid (ชี้ขาด โดยไม่คำนึงถึงการตรวจสอบอื่น)
การยืนยันตัวตน CMS ล้มเหลว ไม่มีการกู้คืนวัสดุของผู้ลงนามError
การยืนยันตัวตน CMS ล้มเหลว มีวัสดุของผู้ลงนามอยู่Invalid
ยืนยันตัวตนได้ แต่ห่วงโซ่ไม่ผ่านการตรวจสอบInvalid (หรือ Error เมื่อไม่มีห่วงโซ่)
ยืนยันตัวตนได้และห่วงโซ่ถูกต้อง แต่ไม่มี trust anchor ที่ยืนยันแล้วIndeterminate
ยืนยันตัวตนได้ ห่วงโซ่ถูกต้อง เชื่อถือได้ แต่ไม่มีการยืนยันการไม่ถูกเพิกถอนที่ชี้ขาดIndeterminate
ทั้งหมดข้างต้นได้รับการยืนยันอย่างชัดเจนValid

กฎการไม่ถูกเพิกถอนแบบชี้ขาด “ยังไม่พิสูจน์ว่าถูกเพิกถอน” ไม่เหมือนกับ “พิสูจน์แล้วว่าไม่ถูกเพิกถอน” ผลตัดสิน Valid ต้องมีผลการเพิกถอน Good อย่างน้อยหนึ่งรายการ การตอบสนอง OCSP ที่ยืนยันว่าดีคือรูปแบบที่ชี้ขาด เพราะมันยืนยันสถานะของใบรับรองผู้ลงนามเอง CRL ที่ผ่านการยอมรับเชิงวิทยาการเข้ารหัสลับและสดใหม่ก็ผ่านเกณฑ์นี้ในการนำไปใช้งานนี้เช่นกัน แต่เป็นเพียงการรับรองความสดใหม่และความสมบูรณ์เท่านั้น — เส้นทางนี้ไม่ได้แจงรายการตามหมายเลขซีเรียลแต่ละรายการ จึงไม่ให้การรับประกันการเพิกถอนในระดับซีเรียล และไม่เคยให้ผลตัดสิน revoked เชิงบวก ควรกำหนดค่า OCSP ทุกที่ที่การตรวจจับการเพิกถอนเชิงบวกมีความสำคัญ การติดตั้งที่ใช้เพียง CRL จะไม่แสดงใบรับรองที่ถูกเพิกถอนเป็น Invalid เมื่อผลลัพธ์ทั้ง OCSP และ CRL เป็น Unknown หรือ Unavailable สถานะการเพิกถอนจะไม่ถูกกำหนด และผลตัดสินจะเป็น Indeterminate ซึ่งเป็นไปตาม ETSI EN 319 102-1 คือ ข้อมูลสถานะการเพิกถอนที่ไม่พร้อมใช้งานจะให้ผลเป็น INDETERMINATE ไม่ใช่การผ่าน (ข้อ 5.1.3, TRY_LATER) นี่คือการเพิ่มความเข้มงวดของพฤติกรรมในเวอร์ชัน 3.1.0 ที่มีผลต่อความเข้ากันได้ย้อนหลัง: รุ่นก่อนหน้าอาจรายงาน Valid โดยไม่มีหลักฐานการเพิกถอนที่ชี้ขาด การติดตั้งที่ไม่ได้กำหนดค่าไคลเอนต์ OCSP หรือ CRL ตอนนี้จะพบ Indeterminate โดยทั่วไปในจุดที่ก่อนหน้านี้เคยเห็น Valid

มีสองขอบเขตที่กำหนดกรอบความสามารถนี้อย่างตรงไปตรงมา ประการแรก ตัวตรวจสอบแบบกลุ่มไม่ได้ประเมินโทเคนการประทับเวลาที่ฝังอยู่ TimestampStatus ในผลลัพธ์แบบกลุ่มจะเป็นสถานะไม่ปรากฏเสมอ การประเมินการประทับเวลา RFC 3161 เป็นของฝั่งตรวจสอบเอกสารเดี่ยว ดูที่ การตรวจสอบลายเซ็น ประการที่สอง หน้านี้เป็นการตรวจสอบแบบอ่านอย่างเดียว การฝังวัสดุ DSS/VRI เพื่อความถูกต้องระยะยาวเป็นความสามารถของ การจัดเก็บถาวร

การตัดสินใจที่สำคัญคือตัวผลิตผลตัดสินแบบ fail-closed Valid จะถูกสร้างขึ้นจากหลักฐานเชิงยืนยันบนทั้งสามแกนเท่านั้น ได้แก่ การยืนยันตัวตนเชิงวิทยาการเข้ารหัสลับ ห่วงโซ่ที่ยึดกับ trust anchor และการไม่ถูกเพิกถอนที่ชี้ขาด สิ่งใดที่ยังไม่ได้รับการยืนยันจะลดระดับลงเป็น Indeterminate แทนที่จะกำหนดค่าเริ่มต้นเป็นการผ่าน ซึ่งเป็นท่าทีของ EN 319 102-1 สำหรับวัสดุการเพิกถอนที่ขาดหายไป ปริมาณงานแบบกลุ่มไม่เคยแลกความเข้มงวดกลับมา ชั้นแบบกลุ่มเป็นการจัดการเหนือตัวตรวจสอบ CMS ที่ผ่านการตรวจสอบเดียวกันกับที่ใช้กับเอกสารเดี่ยว ดังนั้นการทำงานกับเอกสาร 1,000 ฉบับจึงใช้วิทยาการเข้ารหัสลับที่เหมือนกัน รายงานยังแยกหลักฐานออกจากผลตัดสิน — CertChainStatus และ RevocationStatus บันทึกอินพุตที่ผลตัดสินแต่ละรายการตั้งอยู่ เพื่อให้ผู้ตรวจสอบสามารถอนุมานใหม่ได้ในภายหลัง

ที่มาของการออกแบบ: การลงนามในปริมาณมากโดยไม่ลดทอนคุณภาพ

สัญลักษณ์ทั้งหมดด้านล่างเป็น public API ใน nextpdf/enterprise 3.1.0

final class BatchSignatureValidator
{
public function __construct(
?SignatureExtractor $extractor = null,
?CertificateChainValidator $chainValidator = null,
private readonly ?OcspClient $ocspClient = null,
private readonly ?CrlFetcher $crlFetcher = null,
?CmsSignatureDataExtractor $cmsExtractor = null,
private readonly ClockInterface $clock = new SystemClock(),
)
public function validate(array $inputs): BatchValidationReport
}

ส่งข้อยกเว้นหรือล้มเหลวด้วย: validate() ส่ง \InvalidArgumentException หากรายการอินพุตว่างเปล่า และ \OverflowException เมื่อกลุ่มเกิน 1,000 เอกสาร เอกสารที่ไม่ใช่ PDF ที่แจงได้จะไม่ส่งข้อยกเว้น แต่จะกลายเป็นผลลัพธ์ Error ในระดับเอกสาร $clock เป็น Psr\Clock\ClockInterface แบบ PSR-20 ที่ใช้สำหรับการตัดสินความสดใหม่ของ CRL ดังนั้นผลตัดสินจึงกำหนดได้แน่นอนภายใต้นาฬิกาทดสอบที่ตรึงไว้

final readonly class DocumentSignatureInput
{
public string $documentId;
public function __construct(
string $documentId,
public string $pdfData,
public array $trustedCerts = [],
)
}

ส่งข้อยกเว้นหรือล้มเหลวด้วย: \InvalidArgumentException หาก $documentId เป็นสตริงว่าง $trustedCerts เป็นรายการใบรับรอง trust anchor ที่เข้ารหัสแบบ PEM

final readonly class BatchValidationReport
{
public function __construct(
public array $documents,
public int $totalDocuments,
public int $totalSignatures,
public int $totalValid,
public int $totalInvalid,
public float $durationMs,
)
public function allValid(): bool
public function hasDocumentsWithoutSignatures(): bool
public function toJson(?CertPiiGuard $piiGuard = null): string
}

ส่งข้อยกเว้นหรือล้มเหลวด้วย: toJson() ส่ง \JsonException หากการเข้ารหัสล้มเหลว allValid() จะเป็น true ก็ต่อเมื่อมีลายเซ็นและไม่มีรายการใดที่ไม่ถูกต้องเท่านั้น โดยค่าเริ่มต้น toJson() จะใช้ NextPDF\Enterprise\Signature\Eidas\CertPiiGuard ที่ปกป้องความเป็นส่วนตัวโดยค่าเริ่มต้น ซึ่งจะปิดบังชื่อผู้ลงนาม ผู้ออกใบรับรองราก ชื่อ TSA และการวินิจฉัยปัญหาของห่วงโซ่ ดูที่ ระดับการรับประกัน eIDAS สำหรับ API ของตัวป้องกันนี้

final readonly class DocumentValidationResult
{
public function __construct(
public string $documentId,
public DocumentValidationStatus $status,
public array $signatures,
public int $validCount,
public int $invalidCount,
)
public function hasSignatures(): bool
public function totalSignatures(): int
}
enum DocumentValidationStatus: string
{
case AllValid = 'all_valid';
case SomeInvalid = 'some_invalid';
case AllInvalid = 'all_invalid';
case NoSignatures = 'no_signatures';
case Error = 'error';
}

ส่งข้อยกเว้นหรือล้มเหลวด้วย: ไม่มี วัตถุค่าที่ไม่เปลี่ยนแปลงและ enum แบบ backed

final readonly class SignatureValidationResult
{
public function __construct(
public SignatureValidationStatus $status,
public CertChainStatus $certChain,
public TimestampStatus $timestamp,
public RevocationStatus $revocation,
public string $signer,
public string $level = '',
public string $subFilter = '',
public string $reason = '',
)
public function isValid(): bool
}
enum SignatureValidationStatus: string
{
case Valid = 'valid';
case Invalid = 'invalid';
case Indeterminate = 'indeterminate';
case Error = 'error';
}

ส่งข้อยกเว้นหรือล้มเหลวด้วย: ไม่มี $signer คือ subject ของใบรับรองที่ผ่านการตรวจสอบ CMS เมื่อการยืนยันตัวตนสำเร็จ มิฉะนั้นจะเป็นสตริงว่าง $level เป็นป้ายกำกับที่ได้มาจาก SubFilter (ตัวอย่างเช่น B-B สำหรับ ETSI.CAdES.detached) ไม่ใช่การพิจารณาความสอดคล้อง AdES

final readonly class CertChainStatus
{
public function __construct(
public bool $valid,
public bool $trusted,
public int $chainLength,
public string $rootIssuer,
public array $issues = [],
)
public function hasIssues(): bool
}

ส่งข้อยกเว้นหรือล้มเหลวด้วย: ไม่มี $trusted จะถูกตั้งค่าเฉพาะเมื่อมีการยืนยันการเป็นสมาชิกของ trust anchor เท่านั้น ไม่เคยมาจากการที่รายการ anchor ไม่ว่างเปล่า

final readonly class RevocationStatus
{
public function __construct(
public RevocationCheckResult $ocspStatus,
public RevocationCheckResult $crlStatus,
public bool $isRevoked,
public ?DateTimeImmutable $revocationDate = null,
)
public static function unavailable(): self
public function hasConclusiveGood(): bool
}
enum RevocationCheckResult: string
{
case Good = 'good';
case Revoked = 'revoked';
case Unknown = 'unknown';
case Unavailable = 'unavailable';
}

ส่งข้อยกเว้นหรือล้มเหลวด้วย: ไม่มีจากสมาชิกที่แสดง คลาสนี้ยังเปิดเผยแฟกทอรีแบบสแตติกที่ตรวจสอบหลักฐาน (good(), revoked(), fromResults()) ซึ่งจะส่ง \InvalidArgumentException เมื่อสถานะที่อ้างขัดแย้งกับหลักฐาน OCSP/CRL — ผลลัพธ์ที่ถูกเพิกถอนไม่มีทางถูกสร้างเป็นไม่ถูกเพิกถอนได้ หรือในทางกลับกัน hasConclusiveGood() จะเป็น true เฉพาะสำหรับสถานะที่ไม่ถูกเพิกถอนซึ่งมีการตรวจสอบอย่างน้อยหนึ่งรายการเป็น Good เท่านั้น

final readonly class TimestampStatus
{
public function __construct(
public bool $present,
public bool $valid,
public ?DateTimeImmutable $timestampTime = null,
public string $tsaName = '',
public array $issues = [],
)
public static function absent(): self
}

ส่งข้อยกเว้นหรือล้มเหลวด้วย: ไม่มี ในผลลัพธ์แบบกลุ่มนี่จะเป็นสถานะ absent() เสมอ ดูที่ กรณีขอบและข้อควรระวัง

ตรวจสอบเอกสารหนึ่งฉบับและอ่านรายงาน ตัวอย่างนี้ใช้ PDF ที่ไม่ได้ลงนาม ผลลัพธ์จึงกำหนดได้แน่นอน

batch-quick-start.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Signature\BatchSignatureValidator;
use NextPDF\Enterprise\Signature\DocumentSignatureInput;
// A minimal, unsigned PDF: the validator reports it as no_signatures.
$unsigned = "%PDF-1.7\n1 0 obj\n<< /Type /Catalog >>\nendobj\ntrailer\n<< /Root 1 0 R >>\n%%EOF\n";
$validator = new BatchSignatureValidator();
try {
$report = $validator->validate([
new DocumentSignatureInput(documentId: 'doc-001', pdfData: $unsigned),
]);
} catch (\InvalidArgumentException $e) {
// Empty input list, or an empty documentId.
echo 'Rejected: ' . $e->getMessage() . "\n";
exit(1);
}
echo 'Documents: ' . $report->totalDocuments . "\n";
echo 'Signatures: ' . $report->totalSignatures . "\n";
foreach ($report->documents as $doc) {
echo $doc->documentId . ': ' . $doc->status->value . "\n";
}
echo 'All valid: ' . ($report->allValid() ? 'yes' : 'no') . "\n";
echo 'Unsigned documents: ' . ($report->hasDocumentsWithoutSignatures() ? 'yes' : 'no') . "\n";

ผลลัพธ์ที่คาดหวัง:

Documents: 1
Signatures: 0
doc-001: no_signatures
All valid: no
Unsigned documents: yes

โปรดสังเกตว่า allValid() รายงาน no ที่นี่ เพราะมันต้องการลายเซ็นอย่างน้อยหนึ่งรายการและไม่มีผลลัพธ์ที่ไม่ถูกต้อง ดังนั้นชุดลายเซ็นที่ว่างเปล่าจึงไม่มีทางผ่านอย่างเงียบๆ

ตรวจสอบไดเรกทอรีของสัญญาที่ลงนามแล้วด้วยไคลเอนต์การเพิกถอน trust anchor การแบ่งกลุ่มเป็นชิ้น และรายงาน JSON ที่ปกป้องข้อมูล PII

batch-validate-contracts.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Ltv\CrlFetcher;
use NextPDF\Enterprise\Security\Ltv\OcspClient;
use NextPDF\Enterprise\Security\Ltv\OcspResponseCache;
use NextPDF\Enterprise\Signature\BatchSignatureValidator;
use NextPDF\Enterprise\Signature\DocumentSignatureInput;
use NextPDF\Enterprise\Signature\SignatureValidationStatus;
// Any PSR-18 client works; Guzzle shown here.
$httpClient = new \GuzzleHttp\Client(['timeout' => 10]);
// Revocation clients make a conclusive non-revoked (Good) result reachable.
// Without them, every verdict tops out at Indeterminate. The response cache
// lets repeat signers across the batch resolve without extra network calls.
$validator = new BatchSignatureValidator(
ocspClient: new OcspClient($httpClient, cache: new OcspResponseCache()),
crlFetcher: new CrlFetcher($httpClient),
);
// Trust anchors are an input: the chain terminus must match one of these.
$anchors = [(string) file_get_contents('/etc/nextpdf/trust/enterprise-root.pem')];
$inputs = [];
foreach (glob('/var/contracts/signed/*.pdf') ?: [] as $path) {
$inputs[] = new DocumentSignatureInput(
documentId: basename($path),
pdfData: (string) file_get_contents($path),
trustedCerts: $anchors,
);
}
$exit = 0;
// One call is capped at 1,000 documents; chunk larger runs.
foreach (array_chunk($inputs, 1000) as $batch) {
try {
$report = $validator->validate($batch);
// Signer PII is redacted by default in the serialized report.
file_put_contents('/var/log/nextpdf/batch-report.jsonl', $report->toJson() . PHP_EOL, FILE_APPEND); // one JSON document per line
} catch (\InvalidArgumentException | \OverflowException $e) {
fwrite(STDERR, 'Batch rejected: ' . $e->getMessage() . "\n");
exit(2);
} catch (\JsonException $e) {
fwrite(STDERR, 'Report encoding failed: ' . $e->getMessage() . "\n");
exit(3);
}
foreach ($report->documents as $doc) {
foreach ($doc->signatures as $sig) {
if ($sig->status !== SignatureValidationStatus::Valid) {
$exit = 1;
fwrite(STDERR, sprintf(
"%s: %s (chain trusted: %s, revoked: %s)\n",
$doc->documentId,
$sig->status->value,
$sig->certChain->trusted ? 'yes' : 'no',
$sig->revocation->isRevoked ? 'yes' : 'no',
));
}
}
}
}
exit($exit);

ผลลัพธ์ที่คาดหวัง (stderr สำหรับเอกสารหนึ่งฉบับที่หลักฐานการเพิกถอนไม่พร้อมใช้งาน บรรทัดอื่นจะแตกต่างกันไปตามอินพุตของคุณ):

contract-0042.pdf: indeterminate (chain trusted: yes, revoked: no)

รายงาน JSON จะทำให้เขตข้อมูลตัวตนของผู้ลงนามเป็นอนุกรมผ่าน CertPiiGuard เริ่มต้น ดังนั้นรายการในระดับแต่ละลายเซ็นจะมีลักษณะเช่นนี้ (ตัดตอนมาเพื่อประกอบการอธิบาย):

{
"status": "indeterminate",
"signer": "[REDACTED]",
"level": "B-B",
"subFilter": "ETSI.CAdES.detached"
}
  • รายการอินพุตที่ว่างเปล่าจะส่ง \InvalidArgumentException เอกสารมากกว่า 1,000 ฉบับในการเรียกครั้งเดียวจะส่ง \OverflowException ให้แบ่งการทำงานที่ใหญ่กว่าเป็นชิ้น ดังในตัวอย่างการใช้งานจริง
  • การอัปเกรดจากรุ่นก่อนหน้า: เมื่อไม่ได้กำหนดค่าไคลเอนต์ OCSP หรือ CRL การเพิกถอนจะเป็น unavailable ดังนั้นจึงไม่มีลายเซ็นใดที่ถึงระดับ Valid ได้ รุ่นก่อนหน้ารายงาน Valid ที่นี่ ส่วน 3.1.0 รายงาน Indeterminate (ดูที่ ภาพรวมเชิงแนวคิด)
  • ตัวนับในระดับเอกสารมีความเข้มงวด เฉพาะ Valid เท่านั้นที่เพิ่ม validCount ส่วน Invalid, Indeterminate, และ Error ล้วนเพิ่ม invalidCount ดังนั้นเอกสารที่มีลายเซ็นเดียวเป็น Indeterminate จึงรายงานเป็น all_invalid ให้ตรวจสอบที่ status ในระดับแต่ละลายเซ็นเมื่อความแตกต่างนี้มีความสำคัญ
  • การตรวจสอบ OCSP จะทำงานเฉพาะเมื่อห่วงโซ่ที่กู้คืนมีใบรับรองอย่างน้อยสองใบ เพราะการสอบถามต้องใช้ผู้ออกใบรับรอง ห่วงโซ่ที่มีใบรับรองเดียวจะตกไปยังเส้นทาง CRL หรือ unavailable
  • crlStatus ไม่เคยรายงาน revoked ในผลลัพธ์แบบกลุ่ม ทางเลือกสำรอง CRL ยืนยันเพียงความสดใหม่ของรายการเท่านั้น ผลการเพิกถอนที่เชื่อถือได้มาจาก OCSP
  • timestamp จะเป็น absent() เสมอในผลลัพธ์แบบกลุ่ม ตัวตรวจสอบแบบกลุ่มไม่ได้ประเมินโทเคน RFC 3161 ที่ฝังอยู่ ให้ใช้ การตรวจสอบลายเซ็น สำหรับการประเมินการประทับเวลา
  • signer จะว่างเปล่าเมื่อการยืนยันตัวตนล้มเหลว เมื่อมีการตั้งค่า มันคือ subject CN (หรือ O) ของใบรับรองที่ผ่านการตรวจสอบ CMS — ไม่เคยเป็นสตริง /Name ที่ไม่ผ่านการยืนยันจากพจนานุกรมลายเซ็น
  • รายการ trustedCerts ต้องเป็นใบรับรอง PEM รายการ anchor ที่ว่างเปล่าหรือมีรูปแบบผิดจะให้ผลตัดสินห่วงโซ่เชิงโครงสร้างเท่านั้นด้วย trusted: false ซึ่งจำกัดผลตัดสินไว้ที่ Indeterminate
  • ไบต์ที่ไม่ได้ขึ้นต้นด้วยส่วนหัว PDF จะสร้างสถานะ error ในระดับเอกสารพร้อมลายเซ็นศูนย์รายการ — โดยไม่มีข้อยกเว้น
  • toJson() จะปกปิด PII โดยค่าเริ่มต้น ให้ส่ง new CertPiiGuard(disclosePii: true) เฉพาะในกรณีที่คุณมีฐานทางกฎหมายที่มีการบันทึกไว้สำหรับการประมวลผลตัวตนของผู้ลงนามเท่านั้น
  • ตัวผลิตผลตัดสินแบบ fail-closed Valid ต้องการทั้งหมดต่อไปนี้ คือ การยืนยันตัวตน CMS ที่ตรวจสอบแล้วเหนือไดเจสต์ /ByteRange ห่วงโซ่ที่ถูกต้อง การยืนยันการเป็นสมาชิกของ trust anchor และสถานะไม่ถูกเพิกถอนที่ชี้ขาด การตรวจสอบทุกรายการที่ยังไม่ได้รับการยืนยันจะลดระดับผลตัดสิน ไม่มีสิ่งใดกำหนดค่าเริ่มต้นเป็นการผ่าน
  • ไม่มีการฟอกตัวตน ผู้ลงนามที่รายงานคือ subject ของใบรับรองที่ผูกไว้เชิงวิทยาการเข้ารหัสลับ รายการ /Name เป็นข้อมูลเมทาดาทาที่ผู้โจมตีควบคุมได้ และไม่เคยถูกแสดงเป็นผู้ลงนาม
  • อัลกอริทึมที่อ่อนแอไม่มีทางผ่าน ลายเซ็น SHA-1 ที่ผ่านการตรวจสอบยังคงถูกรายงานว่าไม่ถูกต้อง ความถูกต้องเชิงวิทยาการเข้ารหัสลับภายใต้ไดเจสต์ที่อ่อนแอจะไม่ถูกฟอกให้กลายเป็นการผ่านแบบเต็มรูปแบบ
  • ความเชื่อถือเป็นอินพุต ไม่ใช่การอนุมาน anchor ที่คุณจัดหาจะถูกจับคู่กับจุดปลายของห่วงโซ่ด้วยลายนิ้วมือ DER SHA-256 (RFC 5280 §6.1.1) ความสอดคล้องในตัวเองของห่วงโซ่ หรือรายการ anchor ที่ไม่ว่างเปล่าเพียงอย่างเดียว ไม่เคยสร้างความเชื่อถือ
  • การเพิกถอนเป็นสิ่งชี้ขาด คำแถลงการเพิกถอนที่ตรวจสอบแล้วจะบังคับให้เป็น Invalid โดยไม่คำนึงถึงการตรวจสอบอื่นทุกรายการ ส่วนหลักฐานที่ไม่พร้อมใช้งานจะบังคับให้เป็น Indeterminate
  • ความเป็นส่วนตัวโดยค่าเริ่มต้นในผลลัพธ์ที่เป็นอนุกรม toJson() จะปิดบัง CN ของผู้ลงนาม DN ของผู้ออกใบรับรองราก ชื่อ TSA และการวินิจฉัยปัญหาของห่วงโซ่ เว้นแต่คุณจะเลือกไม่ใช้ โดยนำหลักการลดข้อมูลให้น้อยที่สุดตาม GDPR Article 5(1)(c) มาใช้ที่ขอบเขตการทำให้เป็นอนุกรม
  • เวลาที่กำหนดได้แน่นอน การตัดสินความสดใหม่ของ CRL จะอ่านนาฬิกา PSR-20 ที่ฉีดเข้ามา ไม่ใช่นาฬิกาของโฮสต์ ดังนั้นผลตัดสินการเพิกถอนจึงทำซ้ำได้ภายใต้การทดสอบ

NextPDF Enterprise นำพฤติกรรมที่อ้างอิงจาก ETSI EN 319 102-1 (แบบจำลองสถานะการตรวจสอบสามค่าและกฎที่ว่าข้อมูลการเพิกถอนที่ไม่พร้อมใช้งานจะให้ผลเป็น INDETERMINATE) RFC 5652 §5.6 (การคำนวณไดเจสต์ใหม่ฝั่งผู้ตรวจสอบ) และ RFC 5280 §6.1 (trust anchor ในฐานะอินพุตของฝ่ายที่พึ่งพาสำหรับการตรวจสอบเส้นทาง) มาใช้ การรองรับไม่ใช่ความสอดคล้อง และความสอดคล้องไม่ใช่การรับรอง NextPDF ไม่ถือครองการรับรองใดและไม่มอบการรับรองใด ตัวตรวจสอบแบบกลุ่มไม่ใช่บริการตรวจสอบที่ผ่านการรับรอง และสถานะของมันเป็นผลตัดสินเชิงวิศวกรรมที่สอดคล้องกับการจัดหมวดหมู่ของ EN 319 102-1 — ไม่ใช่การบ่งชี้ TOTAL-PASSED/TOTAL-FAILED/INDETERMINATE จากกระบวนการตรวจสอบตามข้อ 5 แบบเต็มรูปแบบ โดยเฉพาะอย่างยิ่ง โหมดกลุ่มไม่ได้ดำเนินการพิสูจน์การมีอยู่หรือการประมวลผลการประทับเวลา ฝั่งตรวจสอบเอกสารเดี่ยวครอบคลุมส่วนนั้น

ตัวตรวจสอบแบบกลุ่มไม่ได้อ้างอิงนโยบายโหมด FIPS ใด และการเปิดใช้งานโหมด FIPS ไม่เปลี่ยนแปลงผลตัดสินแบบกลุ่ม การจัดการอัลกอริทึมฝั่งตรวจสอบของมันถูกกำหนดตายตัวและเป็นแบบ fail-closed คือ ลายเซ็นที่อ่อนแอ (SHA-1) จะไม่เคยถูกรายงานเป็น Valid ไม่ว่าจะเปิดหรือปิดโหมด FIPS นโยบายโหมด FIPS ของ Enterprise ควบคุมฝั่งการลงนาม/การสร้าง ซึ่งมีการบันทึกไว้ใน FIPS 140 — เอกสารอ้างอิงเชิงลึก การรองรับ FIPS 140 เป็นคำแถลงความสามารถ ไม่ใช่การอ้างการตรวจสอบหรือการรับรอง

  • validate() ส่ง \InvalidArgumentException สำหรับรายการที่ว่างเปล่า และ \OverflowException เมื่อเกิน 1,000 เอกสาร เอกสารที่มีรูปแบบผิดจะไม่เคยส่งข้อยกเว้น แต่จะสร้างผลลัพธ์ error ในระดับเอกสาร
  • Valid ต้องการเงื่อนไขร่วมทั้งหมด คือ CMS ที่ตรวจสอบเชิงวิทยาการเข้ารหัสลับแล้ว ห่วงโซ่ที่ถูกต้อง การยืนยันการเป็นสมาชิกของ trust anchor และ RevocationStatus::hasConclusiveGood() เป็นจริง
  • ใบรับรองที่ยืนยันแล้วว่าถูกเพิกถอนเป็นสิ่งชี้ขาด คือ ผลตัดสินจะเป็น Invalid โดยไม่คำนึงถึงหลักฐานอื่นทั้งหมด
  • การตรวจสอบการเพิกถอนทั้งสองเป็น Unknown/Unavailable หมายถึง Indeterminate ไม่ใช่ Valid (การเพิ่มความเข้มงวดในเวอร์ชัน 3.1.0 มีผลต่อความเข้ากันได้ย้อนหลัง)
  • ลายเซ็นที่ยืนยันตัวตนได้และห่วงโซ่ถูกต้องแต่ไม่มี trust anchor ที่ยืนยันแล้วจะเป็น Indeterminate — เป็นของแท้ แต่ยังไม่ได้สร้างความเชื่อถือ
  • signer คือ subject ที่ผ่านการตรวจสอบ CMS หรือสตริงว่าง รายการ /Name จะไม่เคยถูกใช้
  • timestamp จะเป็นสถานะไม่ปรากฏเสมอในผลลัพธ์แบบกลุ่ม
  • validCount นับเฉพาะ Valid เท่านั้น สถานะอื่นทั้งหมดจะนับเข้า invalidCount และสถานะเอกสารจะรวมมาจากตัวนับเหล่านั้น
  • toJson() จะใช้ CertPiiGuard ที่ปกป้องความเป็นส่วนตัวโดยค่าเริ่มต้น เว้นแต่มีการส่งตัวป้องกันมาอย่างชัดเจน
  • ยอดรวมของรายงานเป็นผลรวมที่แม่นยำเหนือผลลัพธ์ในระดับเอกสาร durationMs คือเวลาจริงที่วัดได้สำหรับกลุ่ม

โมดูล ความปลอดภัย / การลงนาม ของ NextPDF Core เป็นฝั่งผู้ผลิต คือ มันสร้างลายเซ็น CMS ใช้การประทับเวลา RFC 3161 และตรวจสอบห่วงโซ่และการเพิกถอนสำหรับวัสดุที่มันฝังในเวลาที่ลงนาม Core ไม่มีตัวจัดการแบบกลุ่มฝั่งตรวจสอบ คือ ไม่มีรายงานหลายเอกสาร ไม่มีการจัดหมวดหมู่สถานะแบบรวม ไม่มีผลตัดสินการเพิกถอน OCSP/CRL สำหรับเอกสารของบุคคลที่สาม และไม่มีการทำให้รายงานเป็นอนุกรมที่ปกป้องข้อมูล PII หากใช้ Core เพียงอย่างเดียว คุณจะต้องสกัดและตรวจสอบแต่ละลายเซ็นด้วยตนเองและสร้างระบบรายงานของคุณเอง ฝั่งตรวจสอบเอกสารเดี่ยวของ Enterprise (การตรวจสอบลายเซ็น) และตัวจัดการแบบกลุ่มนี้ให้ชั้นดังกล่าว

หน้านี้บันทึกเฉพาะพฤติกรรมที่สังเกตได้จากภายนอกและพื้นผิว public API ที่รองรับเท่านั้น เส้นทาง namespace ภายใน คลาสตัวช่วย ตารางกลไก ชื่อไฟล์ runbook และคำนำหน้าตั๋วอยู่นอกขอบเขต