الخلاصة

  • يوقع CertificateVerify سجل المصافحة بمفتاح الشهادة الخاص؛ أما Finished فيوثق حداً لاحقاً بمفتاح مشتق من سر حركة المصافحة الخاص بالمرسل.
  • صحة Finished الخاص بالخادم لا تثبت Finished العميل ولا قبول 0-RTT ولا ساق الوكيل الصاعدة ولا صلاحية التطبيق أو نتيجة دائمة.

وصل إعلان النجاح قبل الرسالة الحاسمة

كانت سلسلة الشهادة واسم الخدمة مقبولين، وكان CertificateVerify صحيحاً. ثم لم يطابق verify_data السجل والمفتاح اللذين حسبهما العميل. تفرض RFC 9846 إنهاءً قاتلاً. لم تكن هناك جلسة ناجحة جزئياً، بل مصافحة فاشلة.

يثبت CertificateVerify التحكم في المفتاح الخاص المرتبط بالاعتماد، ويوقع بنية تفصل دور الخادم عن العميل وتمتد حتى Certificate. وتبقى سياسة السلسلة وهوية الخدمة حكماً مستقلاً.

ليست Finished توقيع شهادة ثانياً. يشتق TLS 1.3 مفتاح finished_key من سر حركة المصافحة للمرسل، ثم يحسب HMAC على السجل حتى CertificateVerify إن وجد. وهكذا يؤكد المفاتيح المحسوبة والتاريخ الدقيق لهذا الاتصال.

قد يغيب Certificate وCertificateVerify في نمط PSK، لكن Finished يبقى إلزامياً. لذلك لا يقوم أحد الدليلين مقام الآخر.

سجل المصافحة ليس تجميعاً للحزم

يشمل التجزئة رسائل المصافحة بترتيبها مع نوع كل رسالة وطولها، ولا يشمل ترويسات السجلات أو التنبيهات أو بيانات التطبيق. لا تغير تجزئة الرسالة بين سجلات متعددة موضوع الإثبات.

بعد HelloRetryRequest يمثل ClientHello الأول برسالة message_hash اصطناعية. كما أن بقية مصافحة TLS 1.3 مشفرة. لذلك يحتاج البناء الدقيق إلى أسرار تشخيصية من الطرف أو دليل مكافئ داخل التنفيذ، لا إلى لصق البايتات المرئية.

تحدد حزمة التشفير دالة التجزئة المستخدمة في السجل وHKDF. يساوي طول verify_data في TLS 1.3 خرج تلك الدالة، لا اثني عشر بايتاً ثابتة كما في TLS 1.2.

لكل اتجاه لحظة اكتمال مختلفة

للعميل والخادم أسرار منفصلة، وقيم Finished مختلفة، وأوقات مختلفة للتحقق من الطرف المقابل. بعد إرسال Finished يستطيع الخادم استعمال مفاتيح التطبيق وإرسال بيانات قبل تلقي Finished العميل. لكنه لا يملك عندئذ ضماناً لهوية العميل أو حضوره، فقد يكون ClientHello معاداً.

يتحقق العميل من الخادم، ويرسل مصادقته إن طلبت، ثم Finished الخاص به. يخفي علم واحد اسمه tls_complete من أرسل ومن تحقق. يجب حفظ finished_sent وpeer_finished_verified وحالة التنفيذ لكل طرف.

يمثل 0-RTT استثناءً صريحاً: يعتمد PSK سابقاً ويمكن إعادته. لذا تفصل حالة عرض البيانات المبكرة وقبولها أو رفضها عن اكتمال المصافحة العادية.

للوكيل تاريخان لا تاريخ واحد

لا تتشارك ساق العميل–الوكيل وساق الوكيل–المصدر سجلاً أو سراً أو Finished. نسخ ملصق الساق السفلى إلى العليا يختلق استمرارية. قد تربط هوية تطبيقية الطلبين، لكن كل ساق تثبت مصافحتها بنفسها.

يفصل OpenSSL بين SSL_is_init_finished() وSSL_get_verify_result() الخاص بالشهادة. يفيد key log في مختبر معزول لكنه يكشف أسراراً. يوثق BoringSSL أن واجهات Finished تعيد صفراً في TLS 1.3، ويقدم GnuTLS hooks وخطأ مخصوصاً. تشابه الأسماء لا يصنع دليلاً قابلاً للنقل.

يبقي الاختبار الحاسم الشهادة وCertificateVerify صحيحين، ويغير بايتاً واحداً في Finished، ثم يطلب فشلاً قاتلاً. وبعده يحجب Finished العميل، ويختبر PSK بلا شهادة، ويفرض HelloRetryRequest، ويكرر عبر ساقين مختلفتين للوكيل. هذا يثبت سلوك الشفرة العاملة؛ وجود واجهة لا يثبت تنفيذها.