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

Enterprise الإصدار

مستويات ضمان eIDAS

يحوّل ⁨NextPDF Enterprise⁩ أدلة قوائم الثقة في الاتحاد الأوروبي إلى مستوى ضمان ⁨eIDAS⁩ صريح (⁨LoA⁩). تصنّف خدمة ⁨NextPDF\Enterprise\Security\Eidas\LoaMapping⁩ إدخال خدمة ثقة واحدًا على أنه ⁨Low⁩ أو ⁨Substantial⁩ أو ⁨High⁩. وتُعيد ⁨LoaAssertion⁩ تحمل المستوى إضافةً إلى رموز أسباب قابلة للقراءة آليًا. يستطيع سير عملك أن يشترط الضمان — «اشترط ⁨High⁩» — وأن يؤرشف الأسباب كأدلة تدقيق. ويقوم حارس مرافق، ⁨CertPiiGuard⁩، بحجب حقول هوية الموقِّع قبل أن تغادر سجلات التدقيق العملية.

يؤطّر حدّان هذه القدرة بأمانة. أولًا، تنتمي الأهلية دائمًا إلى مزوّد خدمة الثقة (⁨TSP⁩) تحت إشراف الدولة العضو. يؤكّد ⁨NextPDF⁩ تصنيفًا على أدلة منشورة؛ لكنه لا يمنح الأهلية ولا يخوّلها ولا يشهد بها أبدًا. ثانيًا، تغطّي هذه الصفحة تأكيد ⁨LoA⁩ وربطه فقط. أما سياسة ⁨PAdES⁩ البِنيوية ⁨eidasQualified()⁩، بما في ذلك معايير نجاحها وفشلها، فمُوثّقة في التحقق.

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

Terminal window
composer require nextpdf/enterprise

تحلّ الحزمة الوصفية ⁨nextpdf/premium⁩ أيضًا حزمة ⁨Enterprise⁩. يستخدم التفعيل غلاف ترخيص ⁨Enterprise⁩ الخاص بك؛ راجع الترخيص والتفعيل. لا تحتاج أصناف ⁨eIDAS⁩ إلى أي امتداد ⁨PHP⁩ يتجاوز خطّ الأساس للمحرك. وهي تُحمَّل تلقائيًا تحت ⁨NextPDF\Enterprise\Security\Eidas⁩ و⁨NextPDF\Enterprise\Signature\Eidas⁩.

تُعرّف اللائحة (EU) رقم 910/2014 (eIDAS) ثلاثة مستويات ضمان: منخفض وجوهري وعالٍ (Article 8(1)). ويعبّر كل مستوى عن درجة من الثقة في هوية مُدّعاة. ويضيف المستوى العالي ضوابط غرضها منع — لا مجرد تقليل — إساءة استخدام الهوية أو تحويرها (Article 8(2)(c)). تُعرّف Article 8 هذه المستويات لأنظمة التعريف الإلكتروني. يعيد ⁨NextPDF⁩ استخدام المفردات نفسها لتصنيف أدلة خدمة الثقة الكامنة خلف شهادة توقيع. وذلك الاستخدام المعاد اصطلاحٌ هندسيّ لاشتراط السياسة والتدقيق، وليس تكافؤًا قانونيًا.

يُنمذج التعداد ⁨LoaLevel⁩ المستويات الثلاثة. وقِيَمه الخلفية هي معرّفات ⁨URI⁩ الخاصة بـ⁨LoA⁩ في ⁨eIDAS⁩ بدلًا من عناوين مجرّدة، بحيث يحمل التأكيد المُخزَّن المعرّف الكامل. تُعطي ⁨rank()⁩ ترتيبًا كليًا (⁨Low⁩ = 1، ⁨Substantial⁩ = 2، ⁨High⁩ = 3)، وتُقارن ⁨meetsOrExceeds()⁩ بحدٍّ أدنى مطلوب.

تحسب ⁨LoaMapping⁩ مستوًى من إدخال واحد في القائمة الموثوقة — ⁨TspService⁩ من نظام القائمة الموثوقة الفرعي في ⁨Enterprise⁩ (⁨NextPDF\Enterprise\Security\Tsl⁩). والربط حتميّ:

دليل القائمة الموثوقةالمستوىرموز الأسباب
حالة الخدمة ليست grantedLowservice_not_granted
نوع الخدمة ليس CA/QCLowservice_not_qualified_ca
CA/QC ممنوحة مع QCWithQSCD ودون QCNoQSCDHighca_qc_with_qscd مع esig_or_eseal أو qc_default
CA/QC ممنوحة خلاف ذلكSubstantialca_qc_no_qscd_or_unspecified

مُؤهِّل ⁨QSCD⁩ (جهاز إنشاء التوقيع المؤهَّل) هو المِحور. بموجب Article 3(12)، يتطلب التوقيع الإلكتروني المؤهَّل شهادةً مؤهَّلة وجهاز إنشاء مؤهَّلًا معًا. لذا فإن تصريح القائمة الموثوقة بأن الشهادات تُدار على ⁨QSCD⁩ هو الدليل الذي يدعم تأكيد ⁨High⁩. ودون هذا التصريح، تظل ⁨CA⁩ مؤهَّلة ممنوحة داعمةً لـ⁨Substantial⁩، لا لـ⁨High⁩ أبدًا.

النتيجة هي ⁨LoaAssertion⁩: المستوى إضافةً إلى قائمة برموز الأسباب. وتتيح الأسباب لمستهلك التدقيق أن يُعيد اشتقاق التصنيف من الدليل نفسه لاحقًا. ويمكن لمُقيِّمي السياسة اللاحقين تسجيل التأكيد جنبًا إلى جنب مع نتيجة التحقق من التوقيع.

تُشحن قطعة إضافية في هذا النموذج: ⁨CertPiiGuard⁩. عند سَلسَلة عناصر التحقق إلى حِزم تدقيق ⁨JSON⁩، تحمل شهادة الموقِّع بيانات شخصية — الاسم الشائع للموضوع (Subject CN)، وسمات البريد الإلكتروني، وسمة ⁨serialNumber⁩ التي قد تُرمِّز معرّفًا وطنيًا للأشخاص الطبيعيين. تشترط GDPR Article 5(1)(c) أن تُقصر المعالجة على ما هو ضروري. لذلك يحجب الحارس تلك الحقول افتراضيًا، مستبدلًا القيم بـ⁨[REDACTED]⁩ مع الحفاظ على الغلاف البِنيوي (حقول المؤسسة والدولة والسلسلة والحالة). ويظل بإمكان المستهلكين التحقق من ما إذا نجح التوقيع دون معرفة مَن وقّع.

القرار الحامل هو فصل تأكيد الضمان عن حُكم التحقق. فالتحقق من التوقيع، وفق ⁨ETSI EN 319 102-1⁩، ينتهي بمؤشّر حالة — ⁨TOTAL-PASSED⁩ أو ⁨TOTAL-FAILED⁩ أو ⁨INDETERMINATE⁩ — وذلك الحُكم يخص طبقة التحقق. أما ربط ⁨LoA⁩ فتصنيف مستقل قابل لإعادة التشغيل على أدلة القائمة الموثوقة، مع رموز أسباب بدلًا من عنوان مجرّد. وهذا يمنع ⁨NextPDF⁩ من أن يقدّم أبدًا ادّعاء ضمان كنتيجة تحقق، أو نتيجة تحقق كمنح أهلية. كما يجعل الربط متحفّظًا بحُكم البناء: الدليل الغائب أو الملتبس يخفض المستوى، ولا يرفعه أبدًا.

خلفية التصميم: التواقيع المؤهَّلة، بشرح مبسّط.

كل الرموز أدناه هي واجهة برمجة عامة في ⁨nextpdf/enterprise⁩ 3.1.0.

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()⁩ فيرمي ⁨\ValueError⁩ على معرّف ⁨URI⁩ غير معروف؛ بينما تُعيد ⁨LoaLevel::tryFrom()⁩ القيمة ⁨null⁩ بدلًا من ذلك.

final class LoaMapping
{
public function loaForService(TspService $service): LoaAssertion
}

يرمي أو يفشل بـ: لا شيء. الطريقة كلّيّة — كل مُدخل ⁨TspService⁩ يُنتج ⁨LoaAssertion⁩.

كائنا نقل البيانات المُدخَلان ⁨NextPDF\Enterprise\Security\Tsl\TspService⁩ و⁨NextPDF\Enterprise\Security\Tsl\TspServiceQualifier⁩ هما كائنا نقل بيانات عامّان مستقرّان (⁨@api⁩). يستشير الربط ⁨TspService::STATUS_GRANTED⁩ و⁨TspService::TYPE_CA_QC⁩، وثوابت المؤهِّل ⁨TspServiceQualifier::QSCD_STATEMENT⁩ (⁨QCWithQSCD⁩) و⁨TspServiceQualifier::NO_QSCD⁩ (⁨QCNoQSCD⁩) و⁨TspServiceQualifier::FOR_ESIG⁩ و⁨TspServiceQualifier::FOR_ESEAL⁩.

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,
) {}
}

يرمي أو يفشل بـ: لا شيء. كائن قيمة غير قابل للتغيير.

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]⁩ بدلًا من إصدار قيمة مُقنَّعة جزئيًا.

حلِّل معرّف ⁨URI⁩ الخاص بـ⁨LoA⁩ وقارنه بحدٍّ أدنى مطلوب.

loa-quick-start.php
<?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: yes
Meets high: no

صنِّف إدخالًا في القائمة الموثوقة، واشترط مستوًى مطلوبًا، وأصدِر سجل تدقيق محجوبًا.

loa-audit-gate.php
<?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()⁩ ⁨\ValueError⁩ على معرّفات ⁨URI⁩ غير المعروفة. استخدم ⁨LoaLevel::tryFrom()⁩ حيث تُفضَّل معالجة ⁨null⁩.
  • تظل أدلة الجهاز المتعارضة متحفّظة. تُربَط خدمة تحمل ⁨QCWithQSCD⁩ و⁨QCNoQSCD⁩ معًا إلى ⁨Substantial⁩، لا ⁨High⁩.
  • تُربَط خدمة ⁨CA/QC⁩ ممنوحة بلا مؤهِّلات إلى ⁨Substantial⁩ مع السبب ⁨ca_qc_no_qscd_or_unspecified⁩ — مؤهَّلة افتراضيًا، والجهاز غير مُثبَت.
  • معرّفات ⁨URI⁩ للمؤهِّلات خارج المجموعة المتتبَّعة لا تؤثّر في التصنيف. والمؤهِّلات غير المعروفة أو المستقبلية لا ترفع المستوى أبدًا.
  • يقرأ الربط حالة الخدمة الراهنة فقط. وهو لا يُقيّم تاريخ ⁨statusStartingTime⁩؛ فنوافذ اللحظة الزمنية تخص طبقة التحقق.
  • خزِّن معرّف ⁨URI⁩ الخلفي للتعداد، لا عدد ⁨rank()⁩ الصحيح. الرُّتَب موجودة للمقارنة فقط.
  • يطوي ⁨CertPiiGuard⁩ اسمًا مجرّدًا دون ⁨=⁩ بالكامل إلى ⁨[REDACTED]⁩؛ والسلاسل الفارغة تمرّ عبر كل الحرّاس دون تغيير.
  • تُكتشَف أسماء ⁨DN⁩ القديمة المفصولة بشرطة مائلة في ⁨OpenSSL⁩ وتُقنَّع بِنيويًا. وتُعامَل ⁨/⁩ داخل قيمة ⁨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⁩ سلوكًا مستنيرًا باللائحة (EU) رقم 910/2014 Article 8 (مستويات الضمان) وArticle 3(12) (عناصر التوقيع الإلكتروني المؤهَّل)، وبمفردات مؤهِّلات القائمة الموثوقة في ⁨ETSI⁩. الدعم ليس مطابقة، والمطابقة ليست اعتمادًا. لا يملك ⁨NextPDF⁩ أي اعتماد ولا يمنح أيًّا منه. ⁨NextPDF⁩ ليس مزوّد خدمة ثقة مؤهَّلًا، ولا هيئة تقييم مطابقة، ولا هيئة إشراف. و⁨LoaAssertion⁩ تصنيفٌ برمجيّ لأدلة منشورة. وهو ليس تقريرًا قانونيًا بالأهلية أو بالضمان، ولا يمكنه أن يجعل توقيعًا مؤهَّلًا.

تواصل اللائحة (EU) 2024/1183 (eIDAS 2) الإشارة إلى مستويات Article 8 وتشترط توفير محافظ الهوية الرقمية الأوروبية عند مستوى الضمان العالي. تستشهد هذه الصفحة بذلك كسياق تنظيمي؛ ولا يقدّم ⁨NextPDF⁩ أي ادّعاء قدرة متعلق بالمحافظ.

أما ما إذا كان توقيع محدد يفي بسياسة بِنيوية موجَّهة نحو ⁨eIDAS⁩ فمسألة منفصلة، يُجيب عنها نموذج التحقق؛ راجع التحقق.

لا تُجري أصناف ⁨LoA⁩ الخاصة بـ⁨eIDAS⁩ أي عمليات تشفيرية — لا تجزئة، ولا تحقق من توقيع، ولا عشوائية. تُخضِع سياسة وضع ⁨FIPS⁩ في ⁨Enterprise⁩ الخياراتِ التشفيرية، فليس لديها ما تُخضِعه في هذا النموذج. وتمكين وضع ⁨FIPS⁩ لا يغيّر ربط ⁨LoA⁩ ولا سلوك حارس بيانات الهوية الشخصية. أما التحقق التشفيري من التواقيع والقوائم الموثوقة فتحكمه نماذج التحقق والأمن، حيث تنطبق سياسة وضع ⁨FIPS⁩.

  • LoaMapping::loaForService()⁩ كلّيّة وحتمية. كل ⁨TspService⁩ يُنتج ⁨LoaAssertion⁩؛ والطريقة لا ترمي أبدًا ولا تستشير ساعة ولا شبكة ولا حالة عالمية.
  • التصنيف متحفّظ. الدليل الغائب أو غير المعروف أو المتعارض يخفض المستوى؛ ولا شيء يرفعه سوى دليل ⁨CA/QC⁩ ممنوحة مع ⁨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⁩، يُعيد كل حارس مُدخَله حرفيًا.
  • مخرجات الحارس ثابتة على مستوى البايت للمُدخَل نفسه.

يتحقّق ⁨NextPDF Core⁩ من تواقيع ⁨PDF⁩ تشفيريًا ويفشل مغلقًا على الأدلة المكسورة. ولا يملك ⁨Core⁩ نموذج قائمة موثوقة للاتحاد الأوروبي، ولا مفردات ⁨LoaLevel⁩، ولا ربط ⁨LoA⁩، ولا حارس بيانات هوية شخصية على طبقة ⁨eIDAS⁩ لسَلسَلة التدقيق. على ⁨Core⁩ وحده، عليك أن تشتقّ تصنيفات الضمان بنفسك من بيانات الثقة التي تصونها، وأن تطبّق حجبك الخاص قبل أن تغادر سجلات التدقيق العملية.

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