تخطَّ إلى المحتوى
getnextpdf.com

Enterprise الإصدار

ربط الثقة في حاويات ⁨ASiC⁩

تجمع حاوية ⁨ASiC⁩ الملفات الموقَّعة مع التواقيع التي تحميها. والسؤال الصعب ليس «هل يُحسَب التوقيع بنجاح؟» بل «مَن يقف خلف الموقِّع؟». تُجيب ⁨NextPDF\Enterprise\Security\Asic\AsicTrustBinder⁩ عن هذا السؤال بالضبط. تُسلِّمها شهادة التوقيع من توقيع الحاوية، وقائمة موثوقة، ووقت تحقق. فتُجيب بكائن ⁨AsicTrustBindingResult⁩: حكم بالثقة/عدم الثقة، وإصدار حزمة المراسي التي بنت عليه قرارها، وأسباب قابلة للقراءة آليًا. كل رفض يسمّي سببه، فتكتب أدلة التدقيق نفسها بنفسها.

ثمة حدٌّ واحد مقصود يستحق التوضيح منذ البداية. هذه الواجهة البرمجية لا تحلّل حاويات ⁨ASiC⁩. أدواتك تفتح الحاوية وتستخرج شهادة التوقيع؛ بينما تملك ⁨NextPDF⁩ قرار الثقة.

تأتي هذه الإمكانية ضمن ⁨NextPDF Enterprise⁩ (⁨nextpdf/enterprise⁩) وتُفعَّل بمظروف ترخيص من فئة ⁨Enterprise⁩. أي عملية نشر دون ذلك الاستحقاق لا تُحمِّل أصناف هذه الإمكانية. قارن الإصدارات واحصل على ترخيص.

Terminal window
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⁩.

تعمل بوابتان مغلقتان عند الفشل قبل أي مقارنة مراسٍ:

  1. حداثة الـ⁨TSL⁩. يجب استبعاد أي قائمة موثوقة انقضت لحظة ⁨NextUpdate⁩ الخاصة بها بوصفها منتهية الصلاحية. تؤكّد ⁨AsicTrustBinder::verify()⁩ الحداثة عند وقت التحقق المُقدَّم قبل اشتقاق أي مرساة واحدة. وأي قائمة قديمة، أو قيمة ⁨NextUpdate⁩ بلا مُحدِّد ⁨UTC⁩ صريح، تُطلِق ⁨TslParseException⁩.
  2. فترة صلاحية الموقِّع. يتطلّب التحقق من المسار وفق ⁨RFC 5280⁩ أن تشمل فترة صلاحية الشهادة وقتَ التحقق. وأي توقيع سليم تعمّيًا كانت شهادته منتهية الصلاحية، أو غير صالحة بعد، في ذلك الوقت يُرفَض برمز سبب دقيق.

عندئذٍ فقط يختبر الرابط شهادة التوقيع في مقابل كل مرساة. والتطابق يُنتج ⁨trusted: true⁩ بسبب ⁨anchor_signature_match⁩. وعدم التطابق يُنتج ⁨trusted: false⁩ بسبب ⁨no_anchor_chain⁩.

قرار التصميم الحامل للأساس هو الفصل الصارم بين آليات الحاوية وقرار الثقة، مع إلزام قرار الثقة بأن يكون صريحًا حيال الوقت. تتباين صيغ الحاويات (⁨ASiC-S⁩ و⁨ASiC-E⁩، وحمولات ⁨CAdES⁩ أو ⁨XAdES⁩)، لكن سؤال الثقة نواةٌ واحدة ثابتة: هل تتسلسل هذه الشهادة إلى مرساة من قائمة موثوقة حديثة عند لحظة مُعلَنة؟ وإبقاء تلك النواة خالية من تحليل ⁨ZIP⁩ و⁨XML⁩ يبقيها صغيرة بما يكفي لاختبارها اختبارًا شاملًا وللإغلاق عند الفشل عند كل بوابة. والمنطق نفسه يمنع افتراضًا صامتًا بقيمة ⁨now⁩: فوقت التحقق يغيّر الحكم، لذا يجب أن يملكه المُستدعي. وتُؤكَّد الحداثة داخل مسار اشتقاق المراسي نفسه، لا في مُتعاون اختياري، بحيث لا يمكن لأي مسار مُنتِج أن يتخطّاها.

خلفية التصميم: كيف يُثبت التوقيع الرقمي هوية الموقِّع.

يأخذ الإنشاء مزوّد المراسي الذي يحوّل القوائم الموثوقة إلى حزم مراسٍ.

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()⁩ — لا تُنشئها يدويًا.

public function buildBundle(TslDocument $tsl, DateTimeImmutable $now): EnterpriseCaTrustAnchorBundle

يُطلِق أو يفشل بـ:TslParseException⁩ إذا كانت الـ⁨TSL⁩ قديمة، أو لم تكن ⁨NextUpdate⁩ الخاصة بها قيمة ⁨UTC⁩ قانونية، أو لم تكن لديها خدمات ⁨CA/QC⁩ نشطة.

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⁩. غير موثوق.

عيّنة برمجية — بداية سريعة

قسم بعنوان «عيّنة برمجية — بداية سريعة»

استخرجت أدوات الحاوية لديك شهادة التوقيع سلفًا. اربطها بقائمة موثوقة لدولة عضو جلبتها وصادقت عليها (راجع القوائم الموثوقة).

asic-trust-binding-quickstart.php
<?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⁩ مُدرَجة:

TRUSTED
Anchors: tsl-eu-seq42
Reasons: anchor_signature_match

عيّنة برمجية — بيئة الإنتاج

قسم بعنوان «عيّنة برمجية — بيئة الإنتاج»

اشتق حزمة المراسي مرة واحدة لكل قائمة موثوقة، ثم تحقّق من كثير من موقِّعي الحاويات في مقابلها. فأي ⁨TSL⁩ قديمة أو غير صالحة للاستخدام تُفشِل الدُّفعة كلها بإغلاق؛ بينما تظهر مشكلات الموقِّعين الأفراد لكل حاوية على حدة.

asic-trust-binding-batch.php
<?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⁩ أي اعتماد ولا تمنح أيًّا منه. أما ما إذا كانت عملية تحقق كاملة تفي بمتطلب قانوني أو شرائي معيّن فهو تقدير يعود لمُقيِّميك.

ينفّذ ربط الثقة فحوص توقيع شهادات ⁨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⁩ المستخرَج، والقائمة الموثوقة، ووقت التحقق.

يتحقّق ⁨NextPDF Core⁩ من تواقيع ⁨PDF⁩ (⁨CMS/PAdES⁩) في مقابل مراسي ثقة تُثبِّتها صراحةً عبر عقد ⁨CaTrustAnchorBundle⁩ الخاص به — راجع أمان ⁨Core⁩. لا يملك ⁨Core⁩ استيعاب القوائم الموثوقة (⁨TSL⁩) ولا ربط ثقة خاصًا بـ⁨ASiC⁩. فباستخدام ⁨Core⁩ وحده، يمكنك صيانة مجموعة المراسي الخاصة بك للتحقق من تواقيع ⁨PDF⁩؛ أما اشتقاق المراسي من قائمة موثوقة وفق ⁨ETSI TS 119 612⁩ وربط موقِّعي حاويات ⁨ASiC⁩ بها فيتطلّب ⁨NextPDF Enterprise⁩.

توثّق هذه الصفحة السلوك القابل للملاحظة خارجيًا وسطح الواجهة البرمجية العامة المدعوم فقط. أما مسارات النطاقات الداخلية، وأصناف المساعدة، وجداول الآليات، وأسماء ملفات كتيّبات التشغيل، وبادئات التذاكر فخارج النطاق.