Enterprise الإصدار
ربط الثقة في حاويات ASiC
نظرة سريعة
قسم بعنوان «نظرة سريعة»تجمع حاوية ASiC الملفات الموقَّعة مع التواقيع التي تحميها. والسؤال الصعب ليس «هل يُحسَب التوقيع بنجاح؟» بل «مَن يقف خلف الموقِّع؟». تُجيب NextPDF\Enterprise\Security\Asic\AsicTrustBinder عن هذا السؤال بالضبط. تُسلِّمها شهادة التوقيع من توقيع الحاوية، وقائمة موثوقة، ووقت تحقق. فتُجيب بكائن AsicTrustBindingResult: حكم بالثقة/عدم الثقة، وإصدار حزمة المراسي التي بنت عليه قرارها، وأسباب قابلة للقراءة آليًا. كل رفض يسمّي سببه، فتكتب أدلة التدقيق نفسها بنفسها.
ثمة حدٌّ واحد مقصود يستحق التوضيح منذ البداية. هذه الواجهة البرمجية لا تحلّل حاويات ASiC. أدواتك تفتح الحاوية وتستخرج شهادة التوقيع؛ بينما تملك NextPDF قرار الثقة.
التوفّر والترخيص
قسم بعنوان «التوفّر والترخيص»تأتي هذه الإمكانية ضمن NextPDF Enterprise (nextpdf/enterprise) وتُفعَّل بمظروف ترخيص من فئة Enterprise. أي عملية نشر دون ذلك الاستحقاق لا تُحمِّل أصناف هذه الإمكانية. قارن الإصدارات واحصل على ترخيص.
التثبيت
قسم بعنوان «التثبيت»composer require nextpdf/enterpriseيتطلّب التفعيل مظروف ترخيص Enterprise الخاص بك. راجع التثبيت والمصادقة. تقع الأصناف الواردة في هذه الصفحة ضمن NextPDF\Enterprise\Security\Asic وNextPDF\Enterprise\Security\Tsl.
نظرة مفاهيمية عامة
قسم بعنوان «نظرة مفاهيمية عامة»تحزم ASiC (حاويات التوقيع المرتبطة، ETSI EN 319 162-1) ملفات البيانات والتواقيع في أرشيف واحد. لا تُضمِّن حاوية ASiC الأساسية سوى تواقيع CAdES أو XAdES الأساسية. ويحمل توقيع CAdES الأساسي شهادة توقيعه داخل SignedData.certificates، لذا يُتوقَّع من المُتحقِّق أن يستخرجها من توقيع الحاوية عندما يكون التوقيع سليم التكوين وتدعمه أدوات الحاوية. تلك الشهادة المستخرَجة هي مُدخَل هذه الواجهة البرمجية.
مصدر الثقة هو قائمة موثوقة وفق ETSI TS 119 612 (TSL): مستند XML موقَّع يُعدِّد مزوّدي خدمات الثقة وشهادات خدماتهم. يحوّل NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider كائن TslDocument محلَّلًا إلى حزمة مراسٍ. ولا يُغذّي مجموعة المراسي سوى الخدمات التي تكون في حالة granted ومن نوع خدمة CA/QC معًا. وتحمل الحزمة سلسلة إصدار مشتقة من الرقم التسلسلي للـTSL والإقليم، إضافة إلى بصمة سلامة SHA-256.
تعمل بوابتان مغلقتان عند الفشل قبل أي مقارنة مراسٍ:
- حداثة الـTSL. يجب استبعاد أي قائمة موثوقة انقضت لحظة
NextUpdate الخاصة بها بوصفها منتهية الصلاحية. تؤكّد AsicTrustBinder::verify() الحداثة عند وقت التحقق المُقدَّم قبل اشتقاق أي مرساة واحدة. وأي قائمة قديمة، أو قيمة NextUpdate بلا مُحدِّد UTC صريح، تُطلِق TslParseException. - فترة صلاحية الموقِّع. يتطلّب التحقق من المسار وفق RFC 5280 أن تشمل فترة صلاحية الشهادة وقتَ التحقق. وأي توقيع سليم تعمّيًا كانت شهادته منتهية الصلاحية، أو غير صالحة بعد، في ذلك الوقت يُرفَض برمز سبب دقيق.
عندئذٍ فقط يختبر الرابط شهادة التوقيع في مقابل كل مرساة. والتطابق يُنتج trusted: true بسبب anchor_signature_match. وعدم التطابق يُنتج trusted: false بسبب no_anchor_chain.
لماذا يعمل بهذه الطريقة
قسم بعنوان «لماذا يعمل بهذه الطريقة»قرار التصميم الحامل للأساس هو الفصل الصارم بين آليات الحاوية وقرار الثقة، مع إلزام قرار الثقة بأن يكون صريحًا حيال الوقت. تتباين صيغ الحاويات (ASiC-S وASiC-E، وحمولات CAdES أو XAdES)، لكن سؤال الثقة نواةٌ واحدة ثابتة: هل تتسلسل هذه الشهادة إلى مرساة من قائمة موثوقة حديثة عند لحظة مُعلَنة؟ وإبقاء تلك النواة خالية من تحليل ZIP وXML يبقيها صغيرة بما يكفي لاختبارها اختبارًا شاملًا وللإغلاق عند الفشل عند كل بوابة. والمنطق نفسه يمنع افتراضًا صامتًا بقيمة now: فوقت التحقق يغيّر الحكم، لذا يجب أن يملكه المُستدعي. وتُؤكَّد الحداثة داخل مسار اشتقاق المراسي نفسه، لا في مُتعاون اختياري، بحيث لا يمكن لأي مسار مُنتِج أن يتخطّاها.
خلفية التصميم: كيف يُثبت التوقيع الرقمي هوية الموقِّع.
سطح الواجهة البرمجية
قسم بعنوان «سطح الواجهة البرمجية»AsicTrustBinder
قسم بعنوان «AsicTrustBinder»يأخذ الإنشاء مزوّد المراسي الذي يحوّل القوائم الموثوقة إلى حزم مراسٍ.
public function __construct( private readonly TslTrustAnchorProvider $anchorProvider,) {}تتحقّق نقطة الدخول الرئيسية من شهادة موقِّع في مقابل قائمة موثوقة:
public function verify( string $signerCertPem, TslDocument $tsl, DateTimeInterface $validationTime,): AsicTrustBindingResult-
$signerCertPem — سلسلة PEM غير فارغة: شهادة التوقيع من توقيع ASiC. -
$tsl — القائمة الموثوقة المحلَّلة والمُصادَق عليها. -
$validationTime — اللحظة التي يجب أن تشملها فترة صلاحية شهادة الموقِّع. لا يوجد افتراض.
يُطلِق أو يفشل بـ: NextPDF\Enterprise\Security\Tsl\TslParseException عندما تكون الـTSL قديمة (انقضى NextUpdate)، أو عندما لا تكون قيمة NextUpdate قيمة UTC قانونية، أو عندما لا تحوي القائمة أي خدمات CA/QC نشطة. أما الموقِّعون غير الموثوقين فلا يُطلقون استثناءً؛ بل يُعيدون نتيجة بـtrusted: false ورمز سبب.
لأحمال الدُّفعات، تحقّق في مقابل حزمة مُنشأة مسبقًا:
public function verifyAgainstBundle( string $signerCertPem, EnterpriseCaTrustAnchorBundle $bundle, DateTimeInterface $validationTime,): AsicTrustBindingResultيُطلِق أو يفشل بـ: لا استثناءات خاصة به؛ كل نتيجة هي AsicTrustBindingResult. احصل على الحزمة من TslTrustAnchorProvider::buildBundle() — لا تُنشئها يدويًا.
TslTrustAnchorProvider
قسم بعنوان «TslTrustAnchorProvider»public function buildBundle(TslDocument $tsl, DateTimeImmutable $now): EnterpriseCaTrustAnchorBundleيُطلِق أو يفشل بـ: TslParseException إذا كانت الـTSL قديمة، أو لم تكن NextUpdate الخاصة بها قيمة UTC قانونية، أو لم تكن لديها خدمات CA/QC نشطة.
AsicTrustBindingResult
قسم بعنوان «AsicTrustBindingResult»public function __construct( public bool $trusted, public string $anchorBundleVersion, public array $reasons,) {}$reasons هي list<non-empty-string> من رموز قابلة للقراءة آليًا. ويسجّل $anchorBundleVersion مجموعة المراسي المستخدَمة، بالصيغة tsl-<territory>-seq<N> (مثل tsl-eu-seq42).
| رمز السبب | المعنى |
|---|---|
anchor_signature_match | تتحقّق شهادة الموقِّع في مقابل مرساة مشتقة من TSL. موثوق. |
no_anchor_chain | لا مرساة في الحزمة تتحقّق من شهادة الموقِّع. غير موثوق. |
signer_cert_expired | يقع وقت التحقق بعد notAfter الخاص بالشهادة. غير موثوق. |
signer_cert_not_yet_valid | يقع وقت التحقق قبل notBefore الخاص بالشهادة. غير موثوق. |
cannot_parse_signer_cert | لا يُحلَّل الـPEM المُقدَّم بوصفه شهادة X.509. غير موثوق. |
عيّنة برمجية — بداية سريعة
قسم بعنوان «عيّنة برمجية — بداية سريعة»استخرجت أدوات الحاوية لديك شهادة التوقيع سلفًا. اربطها بقائمة موثوقة لدولة عضو جلبتها وصادقت عليها (راجع القوائم الموثوقة).
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Asic\AsicTrustBinder;use NextPDF\Enterprise\Security\Tsl\TslParseException;use NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider;use NextPDF\Enterprise\Security\Tsl\TslXmlParser;
// Extracted by YOUR tooling from META-INF/signature.p7s or signatures.xml.$signerCertPem = (string) file_get_contents(__DIR__ . '/asic-signer.pem');
// A trusted list you have already fetched and authenticated.$tslXml = (string) file_get_contents(__DIR__ . '/member-state-tsl.xml');
$binder = new AsicTrustBinder(new TslTrustAnchorProvider());
try { $tsl = (new TslXmlParser())->parse($tslXml);
$result = $binder->verify( signerCertPem: $signerCertPem, tsl: $tsl, validationTime: new DateTimeImmutable('2026-07-03T12:00:00Z'), );} catch (TslParseException $e) { // Fail closed: stale TSL, malformed NextUpdate, or no active CA/QC services. fwrite(STDERR, 'Trusted list rejected: ' . $e->getMessage() . PHP_EOL); exit(1);}
echo $result->trusted ? "TRUSTED\n" : "NOT TRUSTED\n";echo 'Anchors: ' . $result->anchorBundleVersion . "\n";echo 'Reasons: ' . implode(', ', $result->reasons) . "\n";الخرج المتوقَّع لموقِّع صادر عن خدمة CA/QC مُدرَجة:
TRUSTEDAnchors: tsl-eu-seq42Reasons: anchor_signature_matchعيّنة برمجية — بيئة الإنتاج
قسم بعنوان «عيّنة برمجية — بيئة الإنتاج»اشتق حزمة المراسي مرة واحدة لكل قائمة موثوقة، ثم تحقّق من كثير من موقِّعي الحاويات في مقابلها. فأي TSL قديمة أو غير صالحة للاستخدام تُفشِل الدُّفعة كلها بإغلاق؛ بينما تظهر مشكلات الموقِّعين الأفراد لكل حاوية على حدة.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Asic\AsicTrustBinder;use NextPDF\Enterprise\Security\Asic\AsicTrustBindingResult;use NextPDF\Enterprise\Security\Tsl\TslDocument;use NextPDF\Enterprise\Security\Tsl\TslParseException;use NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider;use NextPDF\Enterprise\Security\Tsl\TslXmlParser;
/** * @param array<string, non-empty-string> $signerPemsByContainer PEM per container path. * @return array<string, AsicTrustBindingResult> * @throws TslParseException When no anchor set can be derived from the TSL. */function bindBatch( TslDocument $tsl, array $signerPemsByContainer, DateTimeImmutable $validationTime,): array { $provider = new TslTrustAnchorProvider();
// Derive the anchor set ONCE; a throw here means the trusted list itself // is unusable at this validation time. $bundle = $provider->buildBundle($tsl, $validationTime);
$binder = new AsicTrustBinder($provider);
$results = []; foreach ($signerPemsByContainer as $container => $signerPem) { $results[$container] = $binder->verifyAgainstBundle( signerCertPem: $signerPem, bundle: $bundle, validationTime: $validationTime, ); }
return $results;}
$tsl = (new TslXmlParser())->parse( (string) file_get_contents(__DIR__ . '/member-state-tsl.xml'),);
$signerPems = [ 'invoice-2026-06.asice' => (string) file_get_contents(__DIR__ . '/signer-a.pem'), 'tender-2019.asice' => (string) file_get_contents(__DIR__ . '/signer-b.pem'),];
try { $results = bindBatch( tsl: $tsl, signerPemsByContainer: $signerPems, validationTime: new DateTimeImmutable('now', new DateTimeZone('UTC')), );} catch (TslParseException $e) { // Fail closed for the WHOLE batch: no trustworthy anchor set exists. fwrite(STDERR, 'Anchor derivation failed: ' . $e->getMessage() . PHP_EOL); exit(1);}
foreach ($results as $container => $result) { printf( "%s => %s (%s; anchors %s)\n", $container, $result->trusted ? 'trusted' : 'rejected', implode(',', $result->reasons), $result->anchorBundleVersion, );}الخرج المتوقَّع عند انتهاء صلاحية شهادة أحد الموقِّعين:
invoice-2026-06.asice => trusted (anchor_signature_match; anchors tsl-eu-seq42)tender-2019.asice => rejected (signer_cert_expired; anchors tsl-eu-seq42)الحالات الحدّية والمزالق
قسم بعنوان «الحالات الحدّية والمزالق»- وقت التحقق إلزامي وحاسم. لا يوجد افتراض صامت بقيمة
now. فالتوقيع الذي تحقّق في 2019 يُبلِّغ عن signer_cert_expired عندما تتحقّق عند لحظة في 2026 تجاوزت notAfter. وبالنسبة للمواد التاريخية، مرِّر الوقت الذي تدعمه أدلتك (مثل وقت إثبات الوجود)، لا ساعة الحائط. - الـTSL القديمة تُطلِق استثناءً؛ وليست حكمًا بـ«عدم الثقة». فوجود
TslParseException من verify() أو buildBundle() يعني أن مصدر الثقة غير صالح للاستخدام. عامله بوصفه فشلًا تشغيليًا: حدّث القائمة، ولا تسجّله بوصفه رفضًا لموقِّع. - تُختبر المراسي بوصفها مُصدِرين مباشرين. تُجرَّب كل مرساة بوصفها الشهادة التي وقّعت شهادة الموقِّع. وقوائم TSL الخاصة بالدول الأعضاء في الاتحاد الأوروبي تُدرِج شهادات خدمة CA/QC المُصدِرة، لذا تتطابق الشهادات المؤهّلة للكيان النهائي مباشرة عادةً. أما الموقِّع الصادر عن سلطة تصديق وسيطة ليست هي نفسها خدمة CA/QC نشطة مُدرَجة فيُنتج
no_anchor_chain. - اشتقاق المراسي يُرشِّح بصرامة. فالخدمات المسحوبة، أو من أي نوع غير CA/QC، لا تصبح مراسي أبدًا. وأي قائمة مجموعتها النشطة من CA/QC فارغة تُطلِق استثناءً بدلًا من إنتاج حزمة فارغة.
- يجب أن يكون
NextUpdate بقيمة UTC قانونية. فأي قيمة بلا مُحدِّد Z صريح أو إزاحة عددية تُرفَض بإغلاق عند الفشل، ولا يُعاد تفسيرها أبدًا في المنطقة الزمنية المحلية للخادم. - المُدخَل المُشوَّه يتدهور بدقة. فالـPEM الذي لا يُحلَّل يُعيد
cannot_parse_signer_cert؛ وتُميَّز الشهادة غير الصالحة بعد عن الشهادة المنتهية الصلاحية. - سجّل
anchorBundleVersion. فهو يسمّي مجموعة المراسي الدقيقة (tsl-<territory>-seq<N>) خلف كل حكم، وهو ما سيطلبه المُدقِّق.
ملاحظات أمنية
قسم بعنوان «ملاحظات أمنية»- مغلق عند الفشل بحكم التصميم. تُؤكَّد الحداثة قبل اشتقاق أي مرساة. وتعمل بوابة صلاحية الموقِّع قبل أي مقارنة مراسٍ. ومواد الثقة غير الصالحة للاستخدام تُطلِق استثناءً؛ والموقِّعون المشكوك فيهم يُرفَضون بأسباب. ولا يتدهور أي مسار إلى تمرير صامت.
- ربط الثقة طبقة واحدة، لا التحقق كله. فهذه الواجهة البرمجية لا تتحقّق من قيمة توقيع CAdES فوق محتوى الحاوية، ولا تفحص الإلغاء (لا بحث CRL أو OCSP)، ولا تُصادِق على مستند الـTSL نفسه. صادِق على القائمة عبر مسار القوائم الموثوقة أولًا (راجع القوائم الموثوقة)، وتحقّق من التوقيع تعمّيًا بأدوات التوقيع لديك، وأضف فحص الإلغاء وفق سياستك.
- اختر وقت التحقق عن قصد. فالحكم دالة في الوقت الذي تمرّره. اشتقّه من أدلة جديرة بالثقة (ختم زمني مؤهّل، سجل أرشيفي)، لا من ساعة يمكن لمهاجم التأثير فيها.
- مخرجات الأدلة حتمية. فـ
trusted وanchorBundleVersion وreasons قيم مستقرة قابلة للقراءة آليًا تصلح لسجلات تدقيق موقَّعة.
المطابقة
قسم بعنوان «المطابقة»تدعم AsicTrustBinder سير عمل متوائمًا مع ETSI EN 319 162-1 (حاويات ASiC الأساسية)، وETSI EN 319 122-1 (تواقيع CAdES الأساسية)، وETSI TS 119 612 (القوائم الموثوقة)، وتطبّق بوابة فترة الصلاحية وفق RFC 5280 عند وقت التحقق المُقدَّم.
الدعم ليس مطابقة، والمطابقة ليست اعتمادًا. تُنفِّذ NextPDF الفحوص التي تصفها هذه الصفحة؛ ولم تُعتمَد في مقابل هذه المعايير من أي جهة، واستخدام هذه الواجهة البرمجية لا يجعل مخرجاتك بذاته «مؤهّلة» أو نافذة قانونيًا بموجب eIDAS أو أي نظام آخر. لا تملك NextPDF أي اعتماد ولا تمنح أيًّا منه. أما ما إذا كانت عملية تحقق كاملة تفي بمتطلب قانوني أو شرائي معيّن فهو تقدير يعود لمُقيِّميك.
سلوك وضع FIPS
قسم بعنوان «سلوك وضع FIPS»ينفّذ ربط الثقة فحوص توقيع شهادات X.509 داخل العملية؛ وهو غير موجَّه عبر حارس زمن تشغيل وضع FIPS في Enterprise، وتفعيل وضع FIPS لا يغيّر سلوكه. وهو ليس خدمة تعمية مُعتمَدة وفق FIPS، ولا يُدَّعى أي اعتماد FIPS 140. وينبغي للنشرات ذات التزامات FIPS أن تحدّد نطاق هذه الواجهة البرمجية تبعًا لذلك وأن تراجع سياسة التعمية FIPS 140-2/3.
عقد السلوك
قسم بعنوان «عقد السلوك»- تشتق
verify() المراسي فقط من TSL حديثة عند وقت التحقق المُقدَّم؛ وأي قائمة قديمة أو مشوَّهة تُطلِق TslParseException قبل وجود أي مرساة. - تُشتق المراسي حصرًا من خدمات TSL في حالة granted بنوع خدمة CA/QC؛ وأي مجموعة نشطة فارغة تُطلِق استثناءً.
- يجب أن تشمل فترة صلاحية شهادة الموقِّع وقتَ التحقق؛ والمخالفات تُعيد
signer_cert_expired أو signer_cert_not_yet_valid. - كل نتيجة هي
AsicTrustBindingResult تحمل trusted وanchorBundleVersion ورمز سبب واحدًا على الأقل؛ ولا يوجد حكم بلا سبب. - الموقِّعون غير الموثوقين يُعادون، ولا يُطلَقون استثناءً أبدًا؛ ومواد الثقة غير الصالحة للاستخدام تُطلَق استثناءً، ولا تُعاد بوصفها حكمًا أبدًا.
- لا يحدث تحليل الحاوية أبدًا داخل هذه الواجهة البرمجية؛ فالمُدخَلات هي الـPEM المستخرَج، والقائمة الموثوقة، ووقت التحقق.
البديل في Core
قسم بعنوان «البديل في Core»يتحقّق NextPDF Core من تواقيع PDF (CMS/PAdES) في مقابل مراسي ثقة تُثبِّتها صراحةً عبر عقد CaTrustAnchorBundle الخاص به — راجع أمان Core. لا يملك Core استيعاب القوائم الموثوقة (TSL) ولا ربط ثقة خاصًا بـASiC. فباستخدام Core وحده، يمكنك صيانة مجموعة المراسي الخاصة بك للتحقق من تواقيع PDF؛ أما اشتقاق المراسي من قائمة موثوقة وفق ETSI TS 119 612 وربط موقِّعي حاويات ASiC بها فيتطلّب NextPDF Enterprise.
حدود النشر
قسم بعنوان «حدود النشر»توثّق هذه الصفحة السلوك القابل للملاحظة خارجيًا وسطح الواجهة البرمجية العامة المدعوم فقط. أما مسارات النطاقات الداخلية، وأصناف المساعدة، وجداول الآليات، وأسماء ملفات كتيّبات التشغيل، وبادئات التذاكر فخارج النطاق.
اطّلع أيضًا
قسم بعنوان «اطّلع أيضًا»- القوائم الموثوقة — جلب الـTSL التي تُغذّي مزوّد المراسي والمصادقة عليها وتحليلها.
- التحقق من التواقيع — سطح التحقق في Enterprise لتواقيع PDF.
- سياسة التعمية FIPS 140-2/3 — وضعية وضع FIPS في Enterprise.
- كيف يُثبت التوقيع الرقمي هوية الموقِّع — خلفية من المبادئ الأولى.
- التحقق طويل الأمد — لماذا يهمّ وقت التحقق والأدلة المحفوظة.