كيف تتموضع التوقيعات داخل ملف PDF
ISO 32000-2 §12.8 Spec: ETSI EN 319 142-1 ETSI EN 319 142-1 Spec: RFC 5652 RFC 5652 Evidence: Standard-backed
لمحة سريعة
قسم بعنوان «لمحة سريعة»لا يُغلّف توقيع PDF الملف. بل يُضمَّن داخله: قاموس يُسمّي التوقيع، وملخّص (digest) يُحسَب على نطاق مُعلَن من البايتات يتخطّى عمدًا قيمة التوقيع نفسها. تشرح هذه الصفحة تلك الآلية، وبالقدر نفسه من الأهمية، ما الذي لا تَعِد به.
لماذا يهمّ هذا
قسم بعنوان «لماذا يهمّ هذا»“المستند موقَّع” جملة يستخدمها الناس لاتخاذ القرارات. فيربطونها بدفعة مالية، أو موافقة، أو التزام قانوني. إذا لم تعرف بدقة أيّ البايتات يغطيها التوقيع، فلا يمكنك الجزم بما تثبته نتيجة تحقق صحيحة فعلًا. يمكن أن يحمل ملف PDF توقيعًا صحيحًا تمامًا ومع ذلك يَعرض على القارئ محتوى لم يره الموقِّع قط، لأن ذلك المحتوى أُضيف بعد التوقيع، في منطقة لم يدّعِ التوقيع تغطيتها أبدًا. معرفة أين تبدأ سلطة التوقيع وأين تنتهي هي الفرق بين قرار قابل للدفاع عنه وآخر مبني على افتراض غير مثبت.
النسخة المختصرة
قسم بعنوان «النسخة المختصرة»- يوجد توقيع PDF في قاموس توقيع وحقل توقيع داخل المستند، وليس بوصفه غلافًا خارجيًا.
- تُعلَن البايتات الموقَّعة بواسطة مصفوفة
ByteRange: مقطعان من نوع(offset, length)يغطّيان معًا الملف بأكمله باستثناء قيمة التوقيع السداسية العشرية المحفوظة في مدخلContents. - ملخّص هذين المقطعين المتسلسلين هو ما يحميه التوقيع التشفيري فعلًا.
- أيّ شيء يُلحَق لاحقًا في مراجعة جديدة يقع خارج نطاق البايتات الأصلي. يبقى التوقيع الأصلي صحيحًا؛ فهو لم يدّعِ شيئًا قط بشأن البايتات الجديدة.
- يختلف توقيع الموافقة عن توقيع الاعتماد في النطاق: الاعتماد (DocMDP) يقيّد ما يُسمح به من تغييرات لاحقة؛ أما الموافقة فلا تفعل ذلك.
كيف يتعامل NextPDF مع ذلك
قسم بعنوان «كيف يتعامل NextPDF مع ذلك»يبني NextPDF التوقيع وفق نموذج التنسيق، بترتيب ثابت، بحيث يكون نطاق البايتات دقيقًا لا تقريبيًا.
عندما يكتب المحرّك توقيعًا، يحجز أولًا فتحة ثابتة الحجم لقيمة
Contents ويكتب عنصرًا نائبًا ByteRange بعرض ثابت. وهو
ينتظر حتى يُكتَب المستند بالكامل، بما في ذلك جدول الإسناد
الترافقي وعلامة نهاية الملف. عندئذٍ فقط يحسب الإزاحتين الحقيقيتين،
ويعيد كتابتهما في العنصر النائب دون إزاحة أيّ بايت، ويحسب تجزئة المقطعين،
ثم يضع كائن CMS الناتج في الفتحة المحجوزة. العنصر
النائب مُبطَّن بالأصفار إلى طول ثابت، تحديدًا كي لا يؤدي ملء
الأرقام الحقيقية إلى تحريك البايتات التي تُجزَّأ. هذا هو الترتيب الوحيد الذي
ينتج توقيعًا متّسقًا مع نفسه. يتعامل المحرّك مع أيّ إخفاق في هذا
التسلسل بوصفه خطأً قاطعًا لا تراجعًا صامتًا.
في نمط PDF 2.0، يكون كائن التوقيع نفسه بنية CMS منفصلة
من نوع SignedData. يبيّن قاموس PDF أين وكيف؛ أما كائن CMS
فيحمل مَن والإثبات التشفيري.
- Step 1 of 4: ISO 32000-2 §12.8.1 — ByteRange digest & signature dictionary
- Step 2 of 4: ISO 32000-2 §12.8.3.3 — ETSI.CAdES.detached SubFilter
- Step 3 of 4: ETSI EN 319 142-1 PAdES baseline profile
- Step 4 of 4: RFC 5652 CMS SignedData in Contents
ماذا تقول الأدلة
قسم بعنوان «ماذا تقول الأدلة» Evidence: Standard-backed تُعرَّف هذه الآلية في
Spec: ISO 32000-2, §12.8.1 ISO 32000-2 §12.8.1 . يُحسَب ملخّص نطاق البايتات
على نطاق من البايتات يُشير إليه مدخل ByteRange. ينبغي أن يشمل ذلك النطاق
الملف بأكمله متضمّنًا قاموس التوقيع لكن مستثنيًا
قيمة التوقيع — مدخل Contents. ByteRange هو مصفوفة من
أزواج من الأعداد الصحيحة — الإزاحة الابتدائية والطول. تُستخدَم النطاقات غير المتجاورة
تحديدًا كي يتمكّن الملخّص من إغفال قيمة التوقيع نفسها.
في نمط PDF 2.0، يحدّد Spec: ISO 32000-2, §12.8.3.3 ISO 32000-2 §12.8.3.3 أنه عندما يكون SubFilter هو ETSI.CAdES.detached، تكون قيمة Contents كائن CMS SignedData مُرمَّزًا بترميز DER — وهي البنية ذاتها
Spec: RFC 5652 RFC 5652 يُعرّفها — ونمط PAdES لذلك الكائن
هو ما يصفه Spec: ETSI EN 319 142-1 ETSI EN 319 142-1 .
النطاق ليس موحَّدًا بين كل التوقيعات. Spec: ISO 32000-2, §12.7.4.5 ISO 32000-2 §12.7.4.5 يُعرّف صلاحية MDP: القيمة 0 تجعل التوقيع توقيع موافقة، بينما القيم 1–3 تجعله توقيع اعتماد يقيّد أيّ التعديلات اللاحقة تُبقي المستند مطابقًا. آلية نطاق البايتات نفسها؛ لكن الوعد بشأن المستقبل مختلف.
يُطبّق محرّك NextPDF هذا بالضبط: عنصر نائب ByteRange ثابت العرض، والملخّص المتسلسل ذو المقطعين، وكائن CMS منفصل في فتحة Contents محجوزة، ولا يُنجَز ذلك إلا بعد اكتمال الملف.
مثال عملي
قسم بعنوان «مثال عملي»نادرًا ما تبني ByteRange يدويًا. الغاية من المثال هي إظهار شكل النتيجة كي تتعرّف عليها بسهولة عند فحص ملف موقَّع.
<?php
declare(strict_types=1);
use NextPDF\Security\Signature\ByteRangeCalculator;
// Offsets the engine knows only after the whole PDF is written:// $contentsStart — byte just before the '<' of the hex signature// $contentsEnd — byte just after the '>' that closes it// $fileLength — total file size in bytes$range = ByteRangeCalculator::calculate( contentsStart: $contentsStart, contentsEnd: $contentsEnd, fileLength: $fileLength,);// $range === [0, $contentsStart, $contentsEnd, $fileLength - $contentsEnd]// Segment 1: file start → just before the signature value// Segment 2: just after the signature value → end of file// The signature value itself is the gap. It is never hashed.
$signedMessage = ByteRangeCalculator::extractSignedData($pdfBytes, $range);// $signedMessage is segment 1 concatenated with segment 2 — exactly the// bytes the cryptographic digest is computed over.الفجوة بين المقطعين هي قيمة التوقيع. لا يمكن أن تكون هذه القيمة جزءًا من ملخّصها نفسه، ولهذا يكون النطاق قطعتين لا قطعة واحدة.
سوء فهم شائع
قسم بعنوان «سوء فهم شائع»المأزق هو الاعتقاد بأن توقيعًا صحيحًا يعني أن الملف بأكمله الذي تنظر إليه هو ما جرى توقيعه. وهذا غير صحيح. بل يعني أن البايتات داخل النطاق المُعلَن سليمة. يمكن لمراجعة لاحقة أن تُلحِق محتوى بصورة مشروعة — توقيعًا ثانيًا، أو بيانات نموذج، أو مادة تحقّق — خارج ذلك النطاق. يبقى التوقيع الأول صحيحًا، لكنه لا يقول شيئًا عن الإضافة. يخبرك العارض الصحيح بأن التوقيع يغطّي “المستند كما كان وقت التوقيع”، لا “كل بايت على الشاشة”. معاملة الاثنين كأنهما الشيء نفسه هي الطريقة التي يكتسب بها مستند موقَّع محتوى غير موقَّع يبدو موقَّعًا.
الحدود والقيود
قسم بعنوان «الحدود والقيود»تشرح هذه الصفحة البنية، لا الثقة. إنّ
ByteRange المُكوَّن بشكل صحيح وكائن CMS يخبرانك بأن البايتات سليمة وأيّ مفتاح وقّع
عليها. لكنهما، بمفردهما، لا يخبرانك بما إذا كان ذلك المفتاح يخصّ من
تظنّه، ولا بما إذا كانت شهادته صالحة وقت التوقيع، ولا بما إذا كان قد جرى لاحقًا
إبطالها. ذلك يخصّ مسار الشهادة وعمل الإبطال، ويُغطّى في
التحقّق من توقيع بالشكل الصحيح.
كذلك لا تغطّي هذه الصفحة متى جرى التوقيع بأي
سلطة مستقلّة. وقت التوقيع المُؤكَّد ذاتيًا ليس وقتًا موثوقًا —
انظر الطوابع الزمنية والوقت الموثوق.
يبني NextPDF البنية الموصوفة هنا؛ أما الشهادات ومراسي الثقة
وسلطة الطوابع الزمنية فتوفّرها بيئة نشرك، لا المحرّك.
ما يوفّره المحرّك، حسب الفئة، هو القدرة على بناء البنية:
| Edition | Availability |
|---|---|
| Core | PAdES B-B: قاموس التوقيع، وByteRange ثابت العرض، وكائن CMS SignedData المنفصل الموصوف في هذه الصفحة. |
| Pro | يضيف PAdES B-T — طابعًا زمنيًا موثوقًا على قيمة التوقيع — إلى البنية نفسها. |
| Enterprise | يضيف الأنماط طويلة الأمد (B-LT، B-LTA): مادة تحقّق مُضمَّنة وطوابع زمنية للمستند مُركَّبة على أساس نطاق البايتات نفسه. |
مستندات ذات صلة
قسم بعنوان «مستندات ذات صلة»- التحديثات التزايدية ولماذا تهمّ — لماذا يُبقي الإلحاق، لا إعادة الكتابة، نطاق بايتات التوقيع الأول سليمًا.
- أنماط PAdES الأساسية — ما الذي يُركَّب فوق هذه البنية، وأيّ نمط يحتاجه التزام معيّن.
- التحقّق طويل الأمد — كيف تُضمَّن أدلة التحقّق كي يبقى التوقيع قابلًا للتحقّق لسنوات.
مسرد المصطلحات
قسم بعنوان «مسرد المصطلحات»- قاموس التوقيع — قاموس PDF الذي يُسمّي معالج التوقيع، و
SubFilter، وByteRange، وقيمةContents. ByteRange— مصفوفة من أزواج الأعداد الصحيحة(offset, length)تُعلن البايتات التي يغطّيها ملخّص التوقيع بالضبط.Contents— المدخل السداسي العشري الذي يحفظ قيمة التوقيع (في PDF 2.0، كائن CMSSignedDataمنفصل)؛ وهو مُستثنى من ملخّصه نفسه.- CMS
SignedData— بنية صياغة الرسائل التشفيرية (Cryptographic Message Syntax) (RFC 5652) تحمل شهادة الموقِّع وبايتات التوقيع. - PAdES — التوقيعات الإلكترونية المتقدّمة لـPDF (PDF Advanced Electronic Signatures): نمط ETSI لتوقيعات CMS الخاصة بـPDF، المُعرَّف في سلسلة ETSI EN 319 142.
- توقيع الموافقة — توقيع بصلاحية
MDPقيمتها0؛ وهو يؤكّد المحتوى دون تقييد التغييرات اللاحقة. - توقيع الاعتماد — توقيع بصلاحية DocMDP (
MDP1–3) يُقيّد أيّ التعديلات اللاحقة تُبقي المستند مطابقًا.