Enterprise الإصدار
التحقّق من التوقيعات على دفعات
لمحة سريعة
قسم بعنوان «لمحة سريعة»يتحقّق NextPDF Enterprise من التوقيعات الرقمية عبر العديد من مستندات PDF في استدعاء واحد. تأخذ الدالة NextPDF\Enterprise\Signature\BatchSignatureValidator::validate() قائمة من المستندات وتُرجع كائن BatchValidationReport. يمرّ كل توقيع عبر المسار نفسه الذي يفشل بأمان: مصادقة CMS تشفيرية على نطاق البايتات الموقَّع، والتحقّق من سلسلة الشهادات المثبّتة بمراسٍ موثوقة، وفحص الإبطال عبر OCSP/CRL. يحمل التقرير تفاصيل لكل مستند ولكل توقيع — CertChainStatus وRevocationStatus وTimestampStatus — بحيث تستطيع أدوات الامتثال إعادة اشتقاق كل حُكم من أدلته المسجّلة.
نموذج الأحكام صارم عن قصد. لا يكون التوقيع Valid إلّا عندما تُثبَت كل الأدلة إثباتًا مؤكّدًا. تؤدّي أدلة الإبطال المفقودة إلى Indeterminate، وليس Valid أبدًا. تغطّي هذه الصفحة مُنسّق الدُّفعات وأنواع نتائجه. أمّا جانب التحقّق AdES للمستند المفرد فمُوثَّق في التحقّق من التوقيع. ويُوثَّق تضمين مواد التحقّق طويلة الأمد في الأرشفة.
التوفّر والترخيص
قسم بعنوان «التوفّر والترخيص»تأتي هذه القدرة ضمن NextPDF Enterprise (nextpdf/enterprise) وتُفعَّل عبر مغلّف ترخيص من فئة Enterprise. لا يُحمّل أي نشر لا يملك هذا الاستحقاق فئات هذه القدرة. قارن الإصدارات واحصل على ترخيص.
التثبيت
قسم بعنوان «التثبيت»composer require nextpdf/enterpriseتُوفِّر الحزمة الوصفية nextpdf/premium أيضًا حزمة Enterprise. يستخدم التفعيل مغلّف ترخيص Enterprise الخاص بك؛ راجع الترخيص والتفعيل. تُحمَّل أنواع الدُّفعات تلقائيًا ضمن NextPDF\Enterprise\Signature. ولا حاجة إلى أي امتداد PHP يتجاوز الحدّ الأساسي للمحرّك.
نظرة عامة مفاهيمية
قسم بعنوان «نظرة عامة مفاهيمية»يعالج استدعاء واحد للدالة validate() قائمة من قيم DocumentSignatureInput. يحمل كل مُدخَل مُعرّف مستند، وبايتات PDF الخام، ومراسي ثقة اختيارية مُرمّزة بصيغة PEM. يستخرج المُتحقّق قواميس التوقيع لكل مستند ويُشغّل ثلاث مراحل لكل توقيع.
المرحلة 1 — المصادقة التشفيرية. يُتحقَّق من كتلة CMS/PKCS#7 المنفصلة المأخوذة من /Contents على البايتات التي يغطّيها /ByteRange. يعيد المُتحقّق حساب مُلخّص المحتوى بنفسه ويقارنه بالسمة الموقَّعة messageDigest. ولا يثق أبدًا بمُلخّص وفّره المُنتِج (RFC 5652 §5.6). يجب أن يُتحقَّق من قيمة التوقيع، وأن تكون شهادة التوقيع مرتبطة بـCMS. أمّا غياب /Contents أو /ByteRange أو تشوّههما، أو تعذّر تحليل CMS، أو عدم تطابق المُلخّص، أو فشل فحص التوقيع فكلّها تفشل بأمان. ويُعامَل أي توقيع يُتحقَّق منه تحت SHA-1 على أنه ضعيف ولا يُعدّ نجاحًا كاملًا أبدًا.
المرحلة 2 — التحقّق من السلسلة وتثبيت الثقة. يُتحقَّق من سلسلة الموقِّع المستردّة من CMS باعتبارها مسار الاعتماد المُحتمَل. أمّا trustedCerts التي توفّرها فهي مُدخَل مرساة الثقة، بالمعنى الوارد في RFC 5280 §6.1.1: يجب أن تتطابق نهاية السلسلة مع مرساة موفَّرة عبر بصمة DER SHA-256. ولا يُبلَّغ أبدًا عن ثقة سلسلة متّسقة بنيويًا لا تتطابق نهايتها مع مرساة مُهيّأة. وفي غياب مراسٍ صالحة للاستخدام، يُبلَّغ عن الحُكم البنيوي فقط، ويبقى 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 عند غياب السلسلة) |
| مُصادَق عليه والسلسلة صالحة، لكن لا مرساة ثقة مؤكّدة | 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 من أجل الصلاحية طويلة الأمد فهو من قدرة الأرشفة.
لماذا يعمل بهذه الطريقة
قسم بعنوان «لماذا يعمل بهذه الطريقة»القرار الحامل للثقل هو مُنتِج أحكام يفشل بأمان. لا يُصدَر Valid إلّا من دليل مؤكّد على المحاور الثلاثة جميعها: المصادقة التشفيرية، وسلسلة مثبّتة بمرساة ثقة، وعدم إبطال قاطع. وأي شيء غير مُثبَت ينحدر إلى Indeterminate بدلًا من أن يؤول تلقائيًا إلى نجاح، وهذا هو موقف EN 319 102-1 إزاء مواد الإبطال المفقودة. ولا تشتري الإنتاجية الدُّفعية الصرامة أبدًا: فطبقة الدُّفعات ما هي إلّا تنسيق فوق مُتحقّق CMS المُدقَّق نفسه المستخدَم لمستند مفرد، ولذا فإن تشغيلًا يضمّ 1,000 مستند يطبّق التشفير ذاته. كما يفصل التقرير الدليل عن الحُكم — إذ يسجّل CertChainStatus وRevocationStatus المُدخَلات التي يستند إليها كل حُكم، بحيث يستطيع مُدقّق إعادة اشتقاقه لاحقًا.
خلفية التصميم: التوقيع على نطاق واسع، دون تنازل.
واجهة برمجة التطبيقات (API)
قسم بعنوان «واجهة برمجة التطبيقات (API)»جميع الرموز أدناه هي واجهة API عامة في nextpdf/enterprise 3.1.0.
BatchSignatureValidator
قسم بعنوان «BatchSignatureValidator»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-20 من نوع Psr\Clock\ClockInterface تُستخدَم لقرار حداثة CRL، ولذا تكون الأحكام حتمية تحت ساعة اختبار مُجمّدة.
DocumentSignatureInput
قسم بعنوان «DocumentSignatureInput»final readonly class DocumentSignatureInput{ public string $documentId;
public function __construct( string $documentId, public string $pdfData, public array $trustedCerts = [], )}يرمي أو يفشل بما يلي: \InvalidArgumentException إذا كان $documentId سلسلة نصية فارغة. و$trustedCerts هي قائمة من شهادات مراسي الثقة المُرمّزة بصيغة PEM.
BatchValidationReport
قسم بعنوان «BatchValidationReport»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 الحارس.
DocumentValidationResult وDocumentValidationStatus
قسم بعنوان «DocumentValidationResult وDocumentValidationStatus»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';}يرمي أو يفشل بما يلي: لا شيء. كائن قيمة غير قابل للتغيير وتعداد مدعوم.
SignatureValidationResult وSignatureValidationStatus
قسم بعنوان «SignatureValidationResult وSignatureValidationStatus»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 هو موضوع الشهادة المُتحقَّق منه عبر CMS عند نجاح المصادقة، وإلّا فهو السلسلة النصية الفارغة. و$level هو تسمية مُشتقّة من SubFilter (على سبيل المثال B-B مقابل ETSI.CAdES.detached)، وليست تحديدًا لمطابقة AdES.
CertChainStatus
قسم بعنوان «CertChainStatus»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 إلّا عند تأكّد تطابق العضوية مع مرساة ثقة، ولا تُضبَط أبدًا من مجرّد كون قائمة المراسي غير فارغة.
RevocationStatus وRevocationCheckResult
قسم بعنوان «RevocationStatus وRevocationCheckResult»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.
TimestampStatus
قسم بعنوان «TimestampStatus»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 غير موقَّع، ولذا يكون الخرج حتميًا.
<?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: 1Signatures: 0doc-001: no_signaturesAll valid: noUnsigned documents: yesلاحظ أن allValid() تُبلّغ هنا بـno: فهي تتطلّب توقيعًا واحدًا على الأقل وعدم وجود نتائج غير صالحة، ولذا لا تنجح مجموعة توقيعات فارغة بصمت أبدًا.
مثال برمجي — بيئة الإنتاج
قسم بعنوان «مثال برمجي — بيئة الإنتاج»تحقّق من دليل يضمّ عقودًا موقَّعة مع عملاء إبطال، ومراسي ثقة، وتقسيم دُفعي، وتقرير JSON محمي من الكشف عن البيانات الشخصية.
<?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تكون فارغة عند فشل المصادقة. وعند ضبطها، تكون هي CN (أو O) لموضوع الشهادة المُتحقَّق منها عبر CMS — وليست أبدًا سلسلة/Nameغير المُصادَق عليها من قاموس التوقيع.- يجب أن تكون إدخالات
trustedCertsشهادات بصيغة PEM. وتؤدّي قائمة مراسٍ فارغة أو مشوّهة إلى حُكم سلسلة بنيوي فقط بقيمةtrusted: false، ما يحدّ الحُكم عندIndeterminate. - تُنتج البايتات التي لا تبدأ بترويسة PDF حالة
errorعلى مستوى المستند بصفر توقيعات — دون استثناء. - تحجب
toJson()البيانات الشخصية بشكل افتراضي. مرِّرnew CertPiiGuard(disclosePii: true)فقط حيثما تملك أساسًا قانونيًا موثَّقًا لمعالجة هوية الموقِّع.
ملاحظات أمنية
قسم بعنوان «ملاحظات أمنية»- مُنتِج أحكام يفشل بأمان. يتطلّب
Validكل ما يلي: مصادقة CMS مُتحقَّق منها على مُلخّص/ByteRange، وسلسلة صالحة، وعضوية مؤكّدة في مرساة ثقة، وحالة عدم إبطال قاطعة. وكل فحص غير مُثبَت يُنزِل مستوى الحُكم؛ ولا شيء يؤول تلقائيًا إلى نجاح. - لا تبييض للهوية. الموقِّع المُبلَّغ عنه هو موضوع الشهادة المرتبط تشفيريًا. أمّا إدخال
/Nameفهو بيانات وصفية يتحكّم بها المهاجم ولا يُظهَر أبدًا بوصفه الموقِّع. - الخوارزميات الضعيفة لا تنجح أبدًا. يظلّ توقيع SHA-1 الذي يُتحقَّق منه مُبلَّغًا عنه بأنه غير صالح؛ فالصلاحية التشفيرية تحت مُلخّص ضعيف لا تُبيَّض لتصبح نجاحًا كاملًا.
- الثقة مُدخَل لا استنتاج. تُطابَق المراسي التي توفّرها مع نهاية السلسلة عبر بصمة DER SHA-256 (RFC 5280 §6.1.1). ولا يُثبِت الاتساق الذاتي لسلسلة، أو مجرّد قائمة مراسٍ غير فارغة، الثقة أبدًا.
- الإبطال قاطع. يفرض بيان إبطال مُتحقَّق منه الحُكم
Invalidبغضّ النظر عن كل فحص آخر؛ وتفرض الأدلة غير المتوفّرة الحُكمIndeterminate. - الخصوصية افتراضية في الخرج المُسلسَل. تُخفي
toJson()CN الموقِّع، وDN المُصدِر الجذر، واسم TSA، وتشخيصات مشكلات السلسلة ما لم تختر إلغاء ذلك، مُطبِّقةً تقليل البيانات وفق GDPR المادة 5(1)(c) عند حدّ السَّلسلة. - زمن حتمي. يقرأ قرار حداثة CRL ساعة PSR-20 المحقونة، لا ساعة المضيف الفعلية، ولذا تكون أحكام الإبطال قابلة لإعادة الإنتاج تحت الاختبار.
المطابقة
قسم بعنوان «المطابقة»يُنفّذ NextPDF Enterprise سلوكًا مُستَرشِدًا بـETSI EN 319 102-1 (نموذج حالة التحقّق ثلاثي القيم والقاعدة القائلة بأن معلومات الإبطال غير المتوفّرة تؤدّي إلى INDETERMINATE)، وRFC 5652 §5.6 (إعادة حساب المُلخّص في جانب المُتحقّق)، وRFC 5280 §6.1 (مراسي الثقة بوصفها مُدخَلات الطرف المُعتمِد للتحقّق من المسار). الدعم ليس مطابقة، والمطابقة ليست اعتمادًا. ولا يملك NextPDF أي اعتماد ولا يمنح أيًّا منه. والمُتحقّق الدُّفعي ليس خدمة تحقّق مؤهَّلة، وحالاته أحكام هندسية مُتوائمة مع تصنيف EN 319 102-1 — وليست دلالات TOTAL-PASSED/TOTAL-FAILED/INDETERMINATE من عملية تحقّق كاملة وفق البند 5. وعلى وجه الخصوص، لا يُجري وضع الدُّفعات أي إثبات وجود أو معالجة طابع زمني؛ إذ يغطّي جانب التحقّق للمستند المفرد ذلك المجال.
سلوك وضع FIPS
قسم بعنوان «سلوك وضع FIPS»لا يستشير المُتحقّق الدُّفعي أي سياسة لوضع FIPS، ولا يُغيّر تفعيل وضع FIPS أحكام الدُّفعة. ومعالجته للخوارزميات في جانب التحقّق ثابتة وتفشل بأمان: فالتوقيعات الضعيفة (SHA-1) لا يُبلَّغ عنها أبدًا بأنها Valid، بوضع FIPS أو دونه. أمّا سياسة وضع FIPS في Enterprise فتحكم جانب التوقيع/التوليد، وهي مُوثَّقة في FIPS 140 — المرجع المتعمّق. ودعم FIPS 140 بيان قدرة، لا ادّعاء تحقّق أو اعتماد.
عقد السلوك
قسم بعنوان «عقد السلوك»- ترمي
validate()استثناء\InvalidArgumentExceptionعند قائمة فارغة، و\OverflowExceptionعند تجاوز 1,000 مستند. أمّا المستندات المشوّهة فلا ترمي أبدًا؛ بل تُنتج نتائجerrorعلى مستوى المستند. - يتطلّب
Validاقتران ما يلي: تحقّق CMS تشفيريًا، وصلاحية السلسلة، وتأكّد العضوية في مرساة ثقة، وأن تكونRevocationStatus::hasConclusiveGood()بقيمة true. - الشهادة المؤكّد إبطالها قاطعة: يكون الحُكم
Invalidبغضّ النظر عن كل دليل آخر. - كون فحصَي الإبطال كليهما
Unknown/UnavailableيعنيIndeterminate، وليسValidأبدًا (تشديد 3.1.0، بأثر على التوافق مع الإصدارات السابقة). - التوقيع المُصادَق عليه والصالح السلسلة دون مرساة ثقة مؤكّدة يكون
Indeterminate— أصيل، لكن الثقة غير مُثبَتة. signerهي الموضوع المُتحقَّق منه عبر CMS أو السلسلة النصية الفارغة؛ ولا يُستخدَم إدخال/Nameأبدًا.timestampتكون دائمًا في حالة الغياب في نتائج الدُّفعة.validCountتعدّValidفقط؛ وكل الحالات الأخرى تُحتسَب فيinvalidCount، وتتجمّع حالة المستند من تلك العدّادات.- تطبّق
toJson()حارس الخصوصية الافتراضيCertPiiGuardما لم يُمرَّر حارس صراحةً. - إجماليات التقرير هي مجاميع دقيقة على نتائج كل مستند؛ و
durationMsهي الزمن الفعلي المقيس للدُّفعة.
البديل في Core
قسم بعنوان «البديل في Core»وحدة الأمان / التوقيع في NextPDF Core هي جانب الإنتاج: فهي تُنشئ توقيعات CMS، وتطبّق طوابع RFC 3161 الزمنية، وتتحقّق من السلاسل والإبطال للمواد التي تُضمّنها وقت التوقيع. لكن Core لا يأتي بأي مُنسّق دُفعي في جانب التحقّق: لا تقرير متعدّد المستندات، ولا تصنيف حالة إجمالي، ولا أحكام إبطال OCSP/CRL لمستندات أطراف ثالثة، ولا سَلسلة تقارير محمية من الكشف عن البيانات الشخصية. وعلى Core وحده، سيتعيّن عليك استخراج كل توقيع والتحقّق منه بنفسك وبناء تقاريرك الخاصة. أمّا جانب التحقّق للمستند المفرد في Enterprise (التحقّق من التوقيع) وهذا المُنسّق الدُّفعي فيوفّران تلك الطبقة.
حدود النشر
قسم بعنوان «حدود النشر»تُوثّق هذه الصفحة السلوك القابل للملاحظة خارجيًا وسطح API العام المدعوم فقط. أمّا مسارات مساحات الأسماء الداخلية، والفئات المساعِدة، وجداول الآليات، وأسماء ملفات كتيّبات التشغيل، وبادئات التذاكر فخارج النطاق.
اطّلع أيضًا
قسم بعنوان «اطّلع أيضًا»- التحقّق من التوقيع — جانب التحقّق التشفيري AdES/PAdES للمستند المفرد، بما في ذلك التحقّق من الطابع الزمني وسلسلة الأرشفة
- الأرشفة — تضمين مواد DSS/VRI وطوابع المستند الزمنية من أجل الصلاحية طويلة الأمد
- التحقّق — فحوص سياسة بنيوية للقراءة فقط، دون تشفير
- التوقيع — المرجع المتعمّق — المرجع المتعمّق لوحدة التوقيع
- مستويات ضمان eIDAS — API الخاص بـ
CertPiiGuardوربط مستويات الضمان - التوقيع على نطاق واسع، دون تنازل — مقالة Insider حول تصميم التوقيع والتحقّق عالي الحجم
- التحقّق من التوقيع كما ينبغي — مقالة Insider حول أهمية التحقّق الذي يفشل بأمان