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

الأمان / التوقيع: CMS، والطابع الزمني RFC 3161، وLTV، والثقة

تصف هذه الصفحة سطح التوقيع في ⁨NextPDF Core⁩: إنتاج توقيع بنية إدارة المحتوى (⁨CMS⁩)، وتطبيق طابع زمني وفق طلب التعليقات (⁨RFC⁩) 3161، والتحقّق من سلسلة شهادات وفق ⁨RFC 5280⁩، والتحقّق من الإبطال عبر بروتوكول الحالة الفورية للشهادة (⁨OCSP⁩) وقائمة إبطال الشهادات (⁨CRL⁩). تبقى الصفحة عند مستوى السلوك. فئات التنفيذ في ⁨Core⁩ داخلية: يستهلك كود الإنتاج عقد SignerInterface، وليس الأنواع المحسوسة NextPDF\Security\Signature. المدقّق ومراسي الثقة المُهيّأة لديه هما من يقرّران ما إذا كان التوقيع المُنتَج يتحقّق. تلك النتيجة خارجة عن سيطرة المُنتِج، وتذكرها هذه الصفحة حيثما كان ذلك مهمًّا.

Terminal window
composer require nextpdf/core:^3

يبني ⁨Core⁩ بنية ⁨CMS SignedData⁩ من نطاق البايتات، ثم يخزّنها كبيانات مُرمَّزة وفق قواعد الترميز المميِّز (⁨DER⁩) في مدخل قاموس التوقيع Contents — ⁨ISO 32000-2⁩ §12.8.1. تحمل البنية سمات ⁨SignerInfo⁩ المُوقَّعة، بما فيها ⁨content-type⁩ و⁨message-digest⁩ — ⁨RFC 5652⁩ §5.3. يعيد المدقّق حساب موجز المحتوى ويقارنه بسمة ⁨message-digest.⁩ يجب أن تكون نتيجة المقارنة متطابقة حتى يكون التوقيع صالحًا — ⁨RFC 5652⁩ §5.4. يحمل ⁨SignerInfo⁩ أيضًا معرّف خوارزمية الموجز وكتلة السمات المُوقَّعة — ⁨RFC 5652⁩ §5. يستخدم ⁨Core⁩ phpseclib3 لمسارات التوقيع البرمجية التي يشحنها: ⁨RSA⁩ و⁨RSASSA-PSS⁩ و⁨ECDSA⁩ و⁨Ed25519.⁩

طابع ⁨RFC 3161⁩ الزمني هو تبادل طلب واستجابة مع سلطة الطوابع الزمنية (⁨TSA⁩)، وتعيد السلطة بنية ⁨TSTInfo⁩ — ⁨RFC 3161⁩ §2.4.1. يحمل كل رمز serialNumber فريدًا لدى جهة ⁨TSA⁩ المُصدِرة — ⁨RFC 3161⁩ §2.4.2 — وgenTime مُعبَّرًا عنه بالتوقيت العالمي المنسّق (⁨UTC⁩)، وهو لحظة إنشاء الرمز — ⁨RFC 3161⁩ §2.4.2.

للتحقّق من الثقة فحصان. ينتقل التحقّق من المسار من شهادة المُوقِّع إلى مرساة ثقة، مع فحص القيود الأساسية ومُدخَلات بناء المسار — ⁨RFC 5280⁩ §6.1. أما التحقّق من الإبطال فيسأل مُجيب ⁨OCSP⁩ أو يقرأ ⁨CRL⁩: تبلّغ استجابة ⁨OCSP⁩ عن good، أو revoked، أو unknown — ⁨RFC 6960⁩ §2.2 — ويحدّد thisUpdate وnextUpdate في الاستجابة مدى حداثة تلك الحالة — ⁨RFC 6960⁩ §4.2. يزوّد المستدعي مراسي الثقة وسياسة حداثة الإبطال. يتحقّق المحرّك مقابل تلك المُدخَلات ولا يشحن قائمة ثقة مدمجة.

النوعالصنفالدورالاستقرارمنذ
SignerInterfaceواجهة (NextPDF\Contracts)عقد التوقيع الذي يعتمد عليه المستدعونمستقر1.0.0
SignatureLevelتعدادمُحدِّد مستوى توقيعات ⁨PDF⁩ الإلكترونية المتقدّمة (⁨PAdES⁩) ومسبار التوفّرمستقر1.0.0
Rfc5280PathValidatorواجهةنقطة دخول التحقّق من مسار التصديق (validate(...))مستقر (مُجمَّد في 3.1.0)3.1.0
RevocationStatusتعدادمحصّلة ⁨OCSP⁩ / ⁨CRL⁩: ⁨good⁩، ⁨revoked⁩، ⁨unknown⁩مستقر3.1.0
CaTrustAnchorBundleنوعمجموعة مراسي ثقة يزوّدها المستدعيمستقر3.1.0
TstInfoنوعحقول طابع ⁨RFC 3161⁩ الزمني المُحلَّلةمستقر3.2.0

يعيد SignerInterface::sign() القيمة SignatureResult. تنتج طريقته toHex() سلسلة /Contents الست عشرية، وتحمل خاصيته cmsSignedData بايتات ⁨DER⁩ الخام. فئات NextPDF\Security\Signature المحسوسة التي تنفّذ هذا السلوك داخلية (stability: internal في بيان الوحدة). وهي ليست جزءًا من ⁨API⁩ العام وقد تتغيّر دون زيادة في الإصدار الرئيسي. اعتمد على العقود والتعدادات الواردة أعلاه.

examples/contracts/signing-quickstart.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;
/**
* Produce the CMS SignedData hex for a PDF /Contents field.
*
* @param SignerInterface $signer A Core or Premium signer.
* @param string $byteRange The PDF byte range to sign.
*
* @return string Hex-encoded CMS SignedData.
*/
function sign(SignerInterface $signer, string $byteRange): string
{
return $signer->sign($byteRange)->toHex();
}

يعتمد المستدعي على العقد. يستوفي كلٌّ من موقّع ⁨Core⁩ البرمجي وموقّع وحدة أمان العتاد (⁨HSM⁩) في ⁨Premium⁩ العقد SignerInterface، لذلك لا تتغيّر هذه الشيفرة بين الإصدارات.

examples/contracts/signing-trust.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;
use NextPDF\Contracts\TimestampProviderInterface;
use NextPDF\Exception\NextPdfException;
use Psr\Log\LoggerInterface;
final readonly class TimestampedSigner
{
public function __construct(
private SignerInterface $signer,
private TimestampProviderInterface $timestamps,
private LoggerInterface $logger,
) {}
/**
* Sign a byte range, then timestamp the CMS structure.
*
* The timestamp's trust still depends on the verifier accepting the
* Time-Stamping Authority; this method only produces the structure.
*
* @param string $byteRange The PDF byte range to sign.
*
* @return array{cms: string, tst: string}
*/
public function sign(string $byteRange): array
{
try {
$signature = $this->signer->sign($byteRange);
$token = $this->timestamps->getTimestamp($signature->cmsSignedData);
return ['cms' => $signature->toHex(), 'tst' => $token];
} catch (NextPdfException $e) {
$this->logger->error('Signing failed', ['error' => $e->getMessage()]);
throw $e;
}
}
}

يُحقَن مزوّد الطابع الزمني كي يتمكّن أي نشر من تثبيت سلطة الطوابع الزمنية الخاصة به. تسجّل كتلة ⁨catch⁩ الخطأ وتعيد رميه. وهي لا تبتلع الفشل أبدًا، لذلك يبقى مسار التوقيع مغلقًا عند الفشل.

  • التوقيع المُنتَج ليس توقيعًا مُتحقَّقًا منه. يجري التحقّق من المسار والإبطال عند المدقّق، باستخدام مراسي الثقة الخاصة بذلك المدقّق. لا يستطيع المُنتِج تأكيد النتيجة.
  • يستبعد موجز نطاق البايتات قيمة التوقيع. الموجز الذي يغطّي بايتات Contents لا يمكن أن يتحقّق — ⁨ISO 32000-2⁩ §12.8.1.
  • لحالة الإبطال نافذة حداثة. تكون استجابة ⁨OCSP⁩ حديثة فقط ضمن فترة thisUpdate / nextUpdate الخاصة بها — ⁨RFC 6960⁩ §4.2. الاستجابة القديمة ليست بديلًا عن فحص حديث وقت التحقّق.
  • لا يشحن المحرّك قائمة ثقة مدمجة. يزوّد المستدعي CaTrustAnchorBundle؛ والحزمة الفارغة تعني، عمدًا، عدم تحقّق أي سلسلة.
  • ⁨OCSP⁩ unknown ليست good. عامِل unknown على أنها حالة غير محسومة، لا تمريرًا ضمنيًّا — ⁨RFC 6960⁩ §2.2.
  • حفظ مفاتيح ⁨HSM⁩، والتوقيع المؤجّل والسحابي، ومُنتِج ⁨PAdES B-LT⁩ / ⁨B-LTA⁩ ليست في ⁨Core.⁩ يفشل اختيار تلك المسارات في توزيعة ⁨Core⁩ فشلًا مغلقًا برسالة تسمّي مكوّن ⁨Enterprise⁩ المفقود.

يستغرق التوقيع البرمجي عددًا من خانة واحدة من المللي ثانية. يضيف الطابع الزمني رحلة شبكة ذهابًا وإيابًا واحدة إلى ⁨TSA.⁩ يكون التحقّق من المسار محليًّا بمجرّد وجود الشهادات في الذاكرة؛ ويضيف الإبطال جلب ⁨OCSP⁩ أو ⁨CRL⁩ واحدًا لكل شهادة في السلسلة. تغطّي ميزانية الجدار البالغة 1500 ⁨ms⁩ توقيعًا واحدًا مختومًا زمنيًّا مع ⁨TSA⁩ بعيدة على اتصال دافئ. يتجاوز الإبطال مقابل نقطة نهاية بطيئة تلك الميزانية، ومكانه خارج مسار الطلب. سمة قابلية إعادة الإنتاج هي structural: يضمّن الطابع الزمني لحظة التوقيع، لذلك يختلف تشغيلان في بايتات الطابع الزمني بينما تبقى بنية المستند متطابقة.

هذا هو الحدّ التشفيري الأساسي للمحرّك، لذلك يأتي نموذج التهديد صريحًا. يحسب المحرّك نطاق البايتات ولا يقبله من المستدعي أبدًا. مسار التوقيع مغلق عند الفشل: أي فشل في عملية أوّلية أو فجوة في القدرة يرفع استثناءً مُنمَّطًا، ولا يخفّض الخوارزمية بصمت إلى خوارزمية أضعف أبدًا. عند مستوى يتطلّب طابعًا زمنيًّا (⁨B-T⁩، ⁨B-LT⁩، ⁨B-LTA⁩)، تكون سلطة الطوابع الزمنية التي تعيد رمزًا فارغًا خطأً نهائيًّا: يُرفض التوقيع، ولا يُصدَر بصمت في حالة غير مختومة ومنخفضة المستوى، ما لم يُوصَل معالِج خطأ لاعتماد تدهور موثَّق. يتحكّم المستدعي في الثقة عن قصد: المراسي وسياسة الإبطال مُدخَلات، وليست قيمًا افتراضية للمحرّك، لأن المُنتِج الذي يؤكّد ثقته الخاصة سيؤكّد حقيقةً لا يستطيع إثباتها إلا المدقّق. تختزل الثقة في الطابع الزمني إلى الثقة في سلطة الطوابع الزمنية، وهي قابلة للحقن كي يتمكّن أي نشر من تثبيت سلطته الخاصة. هذه الصفحة موسومة بـexport_control_class: legal-review-required لأنها تتعلّق بالتوقيع التشفيري؛ فكل مصدر معياري مُعاد صياغته، ولا يُستنسخ أيٌّ منه، حفاظًا على نظافة الاستشهاد.

الادّعاءالمعيارالبندالدليل
يُخزَّن توقيع ⁨CMS⁩ مُرمَّزًا بـ⁨DER⁩ في مدخل قاموس التوقيع Contents.⁨ISO 32000-2⁩§12.8.1
⁨SignerInfo⁩ يحمل سمتي ⁨content-type⁩ و⁨message-digest⁩ المُوقَّعتين.⁨RFC 5652⁩§5.3
يعيد المدقّق حساب موجز المحتوى ويقارنه بسمة ⁨message-digest.⁩⁨RFC 5652⁩§5.4
تُنتِج رمز الطابع الزمني جهة ⁨RFC 3161 TSA⁩، ويحمل ⁨serialNumber⁩ فريدًا و⁨genTime⁩ بتوقيت ⁨UTC.⁩⁨RFC 3161⁩§2.4.1، §2.4.2,,
يفحص التحقّق من مسار التصديق القيود الأساسية ومُدخَلات المسار من المُوقِّع إلى مرساة ثقة.⁨RFC 5280⁩§6.1,
يبلّغ ⁨OCSP⁩ عن ⁨certStatus⁩ بأنها ⁨good⁩ أو ⁨revoked⁩ أو ⁨unknown⁩، مقيّدةً بـ⁨thisUpdate⁩ / ⁨nextUpdate.⁩⁨RFC 6960⁩§2.2، §4.2,

كل البنود مُعاد صياغتها. لا يستنسخ ⁨NextPDF⁩ النص المعياري. راجِع المعايير المنشورة للحصول على الصياغة المرجعية.

يشحن ⁨Core⁩ موقّع ⁨CMS⁩ البرمجي (⁨RSA⁩ و⁨RSASSA-PSS⁩ و⁨ECDSA⁩ و⁨Ed25519⁩)، واستهلاك طابع ⁨RFC 3161⁩ الزمني، والتحقّق من مسار ⁨RFC 5280⁩، والتحقّق من الإبطال عبر ⁨OCSP⁩ / ⁨CRL.⁩ أما حفظ المفاتيح عبر ⁨HSM⁩ ومعايير تشفير المفتاح العام #11 (⁨PKCS⁩#11)، والتوقيع المؤجّل والسحابي، ومُنتِج ⁨PAdES B-LT⁩ و⁨B-LTA⁩، وملف سياسة التشفير وفق المعايير الفيدرالية لمعالجة المعلومات (⁨FIPS⁩) 140-3، فتُشحَن كلها في إصدارَي ⁨Pro⁩ و⁨Enterprise.⁩ يحلّ ⁨Core⁩ هذه في وقت التشغيل مقابل العقد، لذلك لا يحمل المحرّك مفتوح المصدر أي تبعية تجارية، ولا يتغيّر ⁨API⁩ عند الترقية.