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

Enterprise الإصدار

التوقيع عبر وحدة أمان الأجهزة (PKCS#11)

يوقّع ⁨NextPDF Enterprise⁩ ملف ⁨PDF⁩ بمفتاح محفوظ داخل وحدة أمان الأجهزة (⁨HSM⁩). وجّه المُوقِّع نحو رمز ⁨PKCS#11⁩ — بطاقة ذكية، أو رمز الناقل التسلسلي العام (⁨USB⁩)، أو ⁨HSM⁩ متّصل بالشبكة — وتعمل عملية التوقيع على الجهاز. ولا يغادر المفتاح الخاص حدّ الرمز أبدًا. وهذه الصفحة على مستوى السلوك: تذكر ما يفعله المُوقِّع، وما تقدّمه أنت، وأين يتوقّف حفظ المفاتيح عن أن يكون مسؤولية ⁨NextPDF⁩.

يَحلّ مُوقِّع ⁨HSM⁩ عبر عقد مُوقِّع ⁨Core⁩، فيعتمد تطبيقك على العقد لا على نوع ⁨Enterprise⁩ المحدَّد. وهو يوسّع مسار توقيع بنية رسالة التشفير (⁨CMS⁩) نفسه الذي يستخدمه ⁨Core⁩، باستثناء أن العملية التشفيرية تُفوَّض إلى الرمز.

المتطلبات المسبقة مذكورة في الواجهة الأمامية ومكرّرة تحت المتطلبات المسبقة حتى لا تُفاجأ في منتصف المهمّة.

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

ويَشحَن ⁨NextPDF Core⁩ مُوقِّع ⁨CMS⁩ برمجيًّا يحفظ المفتاح داخل العملية أو يقبل واحدًا عبر عقد استراتيجية توقيع ⁨Core⁩؛ ويضيف ⁨NextPDF Pro⁩ استراتيجيات توقيع بعيدة وعبر خدمة إدارة المفاتيح (⁨KMS⁩) السحابية. وحفظ المفاتيح عتاديًّا عبر ⁨PKCS#11⁩ قدرة ⁨Enterprise⁩، ولا يوفّرها ⁨Core⁩ أو ⁨Pro⁩.

يعرض رمز ⁨PKCS#11⁩ كائنات تشفير — شهادات ومفاتيح خاصة — خلف مكتبة مُشترَكة من المُورِّد. ويُكيِّف مُوقِّع ⁨Enterprise⁩ تلك المكتبة:

  1. يفتح المكتبة المُشترَكة للرمز مرّة واحدة لكل عملية ويخزّن مقبض الوحدة مؤقتًا، لأن ⁨PKCS#11⁩ يتطلّب تهيئة الوحدة مرّة واحدة بالضبط لكل عملية.
  2. يفتح جلسة على الفتحة المُعدّة ويسجّل الدخول بـ ⁨PIN⁩ المُقدَّم. ويُصادِق الدخول المستخدم قبل أي عملية مفتاح خاص، وفق ⁨PKCS#11 v3.1 §5.6.8⁩.
  3. يحدّد شهادة التوقيع على الرمز بالوسم، ويقرأ الشهادة بصيغة قواعد الترميز المميّز (⁨DER⁩)، ويكتشف خوارزمية المفتاح العام.
  4. عند التوقيع يحدّد المفتاح الخاص بالوسم — الذي قد يختلف عن وسم الشهادة في بعض الرموز — ويطلب من الرمز حساب التوقيع. وتُمرَّر البيانات المراد توقيعها؛ ويبقى المفتاح على الجهاز.

يدعم المُوقِّع ⁨RSA⁩ بحشو ⁨PKCS#1 v1.5⁩ (⁨SHA-256⁩ و⁨SHA-384⁩ و⁨SHA-512⁩)، و⁨RSA⁩ بحشو مخطط التوقيع الاحتمالي (⁨PSS⁩) حيث يساوي طول الملح طول الملخّص، وخوارزمية التوقيع الرقمي بالمنحنى الإهليلجي (⁨ECDSA⁩) بـ ⁨SHA-256⁩ و⁨SHA-384⁩ و⁨SHA-512⁩. ويُقرَن منحنى ⁨ECDSA⁩ والملخّص اصطلاحيًّا — ⁨P-256⁩ مع ⁨SHA-256⁩، و⁨P-384⁩ مع ⁨SHA-384⁩، و⁨P-521⁩ مع ⁨SHA-512⁩ — باتّباع الاقتران المُوصى به في ⁨RFC 5480⁩. ويُرجِع رمزٌ توقيع ⁨ECDSA⁩ بوصفه تسلسلًا خامًّا للعددين الصحيحين؛ ويحوّله المُوقِّع إلى الصيغة المُرمَّزة بـ ⁨DER⁩ التي يتوقّعها ⁨PDF⁩ و⁨OpenSSL⁩.

لتوليد التوقيع، يُعد مفتاح ⁨RSA⁩ بطول 2048 بت على الأقل ورُتبة منحنى ⁨ECDSA⁩ بطول 224 بت على الأقل الحدّين الأدنيين المقبولين وفق ⁨NIST SP 800-131A Rev.2 §3⁩. وفّر مفتاح رمزك عند تلك الأحجام أو فوقها.

يوجد مسار بديل عبر محرّك ⁨OpenSSL⁩ للرموز المُسنَدة بمحرّك. وعلى ⁨OpenSSL 3.x⁩ لا يعرض امتداد ⁨OpenSSL⁩ في ⁨PHP⁩ واجهة برمجة تطبيق المحرّك (⁨API⁩)، فيُهجَر صنف المحرّك؛ والمسار المُسنَد بمحرّك المدعوم يشغّل ثنائي سطر أوامر ⁨OpenSSL⁩. آثِر مسار ⁨PKCS#11⁩ المباشر حيث يملك رمزك مكتبة ⁨PKCS#11⁩.

القرار الحامل هو أن المفتاح الخاص لا يغادر الرمز أبدًا. لذا يفوّض المُوقِّع العملية التشفيرية إلى الجهاز ولا ينقل عبر وصلة ⁨PKCS#11⁩ سوى البيانات المراد توقيعها. وهو لا يقرأ مادة المفتاح أو يعيد بناءها في ذاكرة ⁨PHP⁩ أبدًا. ويَحلّ عبر عقد HsmSignerInterface في ⁨Core⁩ بدلًا من نوع ⁨Enterprise⁩ محدَّد، فتكون شيفرة التوقيع متطابقة سواء أعاش المفتاح في البرمجيات أم في ⁨KMS⁩ سحابي أم في رمز عتاد. ويخزّن مقبض الوحدة مؤقتًا مرّة واحدة لكل عملية لأن ⁨PKCS#11⁩ يهيّئ كل وحدة مرّة واحدة بالضبط لكل عملية، ثم يحوّل مخرَج ⁨ECDSA⁩ الخام للرمز إلى ⁨DER⁩ ليرى المُتحقِّقون الترميز الذي يتوقّعونه. والحفظ، لا الراحة، هو ما يحدّد الشكل: يبقى حدّ الثقة عند حافة الجهاز.

خلفية التصميم: التوقيع المُسنَد بـ ⁨HSM⁩.

قبل أن توقّع بـ ⁨HSM⁩، أكّد كل بند:

  1. ثبّت ⁨NextPDF Core⁩ وحزمة ⁨Enterprise⁩: composer require nextpdf/core:^3 وcomposer require nextpdf/enterprise.
  2. احتفظ بترخيص ⁨NextPDF Enterprise⁩ فعّال؛ وحُلّ الحزمة مقابل بيانات اعتماد ترخيصك على ⁨Private Packagist⁩.
  3. ثبّت مكتبة ⁨PKCS#11⁩ المُشترَكة من مُورِّد الرمز على المضيف (مثلًا ملف .so على ⁨Linux⁩ أو .dll على ⁨Windows⁩) ودوّن مسارها المطلق، ورقم الفتحة، وأوسام الكائنات.
  4. حمّل امتداد ⁨PHP⁩ ext-pkcs11. وهو غير مُحزَّم مع ⁨PHP⁩ القياسي ويجب تثبيته على حدة. ويرفع مُنشئ المُوقِّع خطأ عملية مُمَيَّع النوع عند غياب الامتداد.

قدّم هذه المدخلات إلى المُوقِّع:

  • مسار المكتبة — المسار المطلق إلى مكتبة ⁨PKCS#11⁩ المُشترَكة من المُورِّد.
  • معرّف الفتحة — رقم فتحة الرمز، عادةً 0.
  • ⁨PIN⁩ — رمز ⁨PIN⁩ للرمز. عامِله بوصفه سرًّا: قدّمه من مدير الأسرار لديك، لا من المصدر أو السجلات أبدًا. ويَسِم المُوقِّع معامل ⁨PIN⁩ حسّاسًا فيُستثنى من تتبّعات المكدّس والتسلسل.
  • وسم الشهادة — وسم كائن الشهادة على الرمز.
  • وسم المفتاح — وسم كائن المفتاح الخاص، عند اختلافه عن وسم الشهادة.
  • السلسلة — شهادات وسيطة اختيارية بصيغة ⁨DER⁩، عندما لا يحملها الرمز.

افحص توفّر الرمز قبل أن تُنشئ المُوقِّع. ويقرأ الإنشاء الشهادة من الرمز، فتفشل فتحة أو وسم مُساءَ إعدادهما سريعًا بخطأ مُمَيَّع النوع بدلًا من الفشل عند التوقيع.

  1. أكّد أن وقت التشغيل يدعم ⁨PKCS#11⁩ بفحص توفّر الامتداد. لا تُنشئ المُوقِّع عند غياب الامتداد.
  2. اقرأ ⁨PIN⁩ من مدير الأسرار لديك إلى متغيّر لا يُسجَّل أبدًا.
  3. أنشئ مُوقِّع ⁨HSM⁩ بمسار المكتبة، والفتحة، و⁨PIN⁩، والأوسام. ويسجّل الإنشاء الدخول ويقرأ الشهادة.
  4. مرّر المُوقِّع إلى مُنسِّق توقيع ⁨Core⁩ عبر HsmSignerInterface. ويحسب المُنسِّق مدى البايتات، ويبني سمات ⁨CMS⁩ الموقَّعة، ويُسلِّم البيانات إلى الرمز، ويجمّع ملف ⁨PDF⁩ الموقَّع.
  5. التقِط أكثر الإخفاقات تحديدًا، وسجّل رسالة بنيوية دون ⁨PIN⁩، وأعِد رفع الاستثناء.
examples/contracts/hsm-signer-availability.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\HsmSignerInterface;
/**
* Build a hardware-token signer only when the runtime supports it.
*
* The concrete PKCS#11 signer is resolved through the Core contract so the
* caller depends on the interface, not the Enterprise implementation type.
* The PIN arrives from a secret resolver; it is never written to source.
*
* @param callable(): bool $pkcs11Available Reports ext-pkcs11 availability.
* @param callable(): HsmSignerInterface $signerFactory Builds the configured token signer.
*
* @throws \RuntimeException When the PKCS#11 extension is not loaded.
*
* @return HsmSignerInterface The token signer, ready for the Core orchestrator.
*/
function resolveHsmSigner(callable $pkcs11Available, callable $signerFactory): HsmSignerInterface
{
if ($pkcs11Available() !== true) {
throw new \RuntimeException(
'PKCS#11 signing requires the ext-pkcs11 extension; install it before signing.',
);
}
return $signerFactory();
}

تُوثَّق توصيلات الإنتاج — قائمة وسائط المُنشئ بالضبط وأنواع الاستثناءات المُمَيَّعة — في مرجع ⁨HSM⁩ العميق.

examples/contracts/hsm-sign-guarded.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\HsmSignerInterface;
use NextPDF\Exception\NextPdfException;
use Psr\Log\LoggerInterface;
final readonly class HsmSigningService
{
public function __construct(
private HsmSignerInterface $signer,
private LoggerInterface $logger,
) {}
/**
* Sign data on the token through the Core HSM contract.
*
* The byte range is computed by the engine, never accepted from the
* caller. The token performs the signing operation; the private key
* does not leave the device.
*
* @param string $data The bytes the orchestrator hands to the token.
* @param string $algorithm The OpenSSL-style signing algorithm identifier.
*
* @throws NextPdfException When the token operation fails.
*
* @return string The raw signature bytes returned by the token.
*/
public function sign(string $data, string $algorithm): string
{
try {
return $this->signer->sign($data, $algorithm);
} catch (NextPdfException $e) {
// Structural message only — never the PIN or key material.
$this->logger->error('HSM signing failed', ['reason' => $e->getMessage()]);
throw $e;
}
}
}

أكّد النتيجة كما يفعل مُتحقِّق:

  1. اقرأ شهادة المُوقِّع والسلسلة بصيغة ⁨DER⁩ من المُوقِّع وأكّد مطابقتهما للشهادة المُوفَّرة على الرمز.
  2. افتح ملف ⁨PDF⁩ الموقَّع في مُتحقِّق مُعدّ بمراسي ثقتك وأكّد الإبلاغ بأن التوقيع سليم تشفيريًّا. والتوقيع المُنتَج ليس توقيعًا مُتحقَّقًا منه؛ وقرار الثقة يخصّ المُتحقِّق ومراسي ثقته، لا المُنتِج.
  3. لتوقيع ⁨ECDSA⁩، أكّد أن التوقيع المُضمَّن مُرمَّز بـ ⁨DER⁩ — إذ يحوّل المُوقِّع المخرَج الخام للرمز نيابةً عنك، فالمُتحقِّق الذي يرفض الصيغة المتسلسلة الخام ينبغي أن يقبل التوقيع المُضمَّن رغم ذلك.
  4. أكّد عدم ظهور أي ⁨PIN⁩ أو وسم رمز أو مادة مفتاح في سجلات تطبيقك.
  • يبقى المفتاح على الرمز. تُسلَّم البيانات المراد توقيعها إلى الرمز؛ وتعمل عملية التوقيع داخل حدّ الرمز. ولا يُحمَّل المفتاح الخاص في ذاكرة ⁨PHP⁩ أبدًا.
  • ⁨PIN⁩ سرّ. وهو معامل إنشاء حسّاس، يُستثنى من السجلات والتسلسل. قدّمه من مدير أسرار. وقد تُقفِل عمليات إعادة المصادقة الفاشلة المتكرّرة ⁨PIN⁩ عند الرمز؛ ويفرض الرمز، لا ⁨NextPDF⁩، تلك السياسة.
  • الفشل بإحكام. يرفع خطأ الرمز أو ⁨HSM⁩ استثناءً مُمَيَّع النوع. ولا يُنتج المُوقِّع نتيجة غير موقَّعة أو موقَّعة جزئيًّا ولا يستبدل خوارزمية أضعف أبدًا.
  • قوّة الخوارزمية. وفّر مفاتيح ⁨RSA⁩ بطول 2048 بت على الأقل ومنحنيات ⁨ECDSA⁩ برُتبة 224 بت على الأقل، وهي الحدود الدنيا المقبولة لتوليد التوقيع وفق ⁨NIST SP 800-131A Rev.2 §3⁩.
  • التوقيع ما بعد الكمّي تجريبي ومُعطَّل افتراضيًّا. يوجد مسار ما بعد كمّي خلف راية اشتراك صريحة. ولا تعترف بعدُ ملفات التعريف الأرشيفية طويلة الأمد للتوقيعات الإلكترونية المتقدمة لـ ⁨PDF⁩ (⁨PAdES⁩) بمجموعات ما بعد الكمّ، ويرفضها أكثر العارضين عند التحقق. لا تفعّله لتوقيعات ⁨PAdES⁩ الإنتاجية.

تتعلّق هذه الصفحة بالتوقيع التشفيري وتكامل وحدة أمان الأجهزة. وكل مصدر معياري مُلخَّص؛ ولا يُعاد إنتاج أي نص معياري. ### حدّ حفظ المفاتيح

يتكامل ⁨NextPDF Enterprise⁩ مع رمز ⁨PKCS#11⁩ أو ⁨HSM⁩. وهو لا يخزّن مفتاح التوقيع أو يولّده أو يضمن أمانه. ويعتمد أمان المفتاح على الرمز أو ⁨HSM⁩، وعلى النشر، وعلى المُشغِّل — لا على ⁨NextPDF Enterprise⁩ وحده. وأنت مسؤول عن توفير الرمز، ومعالجة ⁨PIN⁩، وإعداد الفتحة، والحماية الشبكية لـ ⁨HSM⁩ متّصل بالشبكة.

  • غياب الامتداد. يرفع إنشاء مُوقِّع ⁨PKCS#11⁩ استثناء عملية مُمَيَّع النوع عند عدم تحميل ext-pkcs11. افحص التوفّر أولًا.
  • عدم العثور على الشهادة أو المفتاح بالوسم. يرفع الإنشاء أو التوقيع استثناءً مُمَيَّع النوع يسمّي الكائن المفقود. أكّد الوسم والفتحة.
  • مُسجَّل الدخول بالفعل. عندما تتشارك عدّة مثيلات مُوقِّع وحدةً مُخزَّنة مؤقتًا للفتحة نفسها، يسجّل المُوقِّع الخروج ثم يعيد تسجيل الدخول لتوفير تحقق ⁨PIN⁩ طازج — وهو مطلوب لرموز التحقق من الهوية الشخصية ذات سياسة «⁨PIN⁩ في كل مرّة».
  • خوارزمية غير مدعومة. يرفع طلب خوارزمية لا يعيّنها المُوقِّع خطأ وسيطة بدلًا من التوقيع ببديل.
  • ⁨HSM⁩ الشبكي غير قابل للوصول. يرفع خطأ شبكة أو جهاز استثناءً مُمَيَّع النوع؛ ولا يُنتج المُوقِّع أبدًا مستندًا غير موقَّع بصمت.

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