SSL_CTX_SET_VERIFY(3SSL)

الاسم
SSL_get_ex_data_X509_STORE_CTX_idx, SSL_CTX_set_verify, SSL_set_verify, SSL_CTX_set_verify_depth, SSL_set_verify_depth, SSL_verify_cb, SSL_verify_client_post_handshake, SSL_set_post_handshake_auth, SSL_CTX_set_post_handshake_auth - ضبط معاملات SSL/TLS مختلفة للتحقق من شهادة النظير

موجز
 #include <openssl/ssl.h>

 typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx);

 void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, SSL_verify_cb verify_callback);
 void SSL_set_verify(SSL *ssl, int mode, SSL_verify_cb verify_callback);
 SSL_get_ex_data_X509_STORE_CTX_idx(void);

 void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth);
 void SSL_set_verify_depth(SSL *ssl, int depth);

 int SSL_verify_client_post_handshake(SSL *ssl);
 void SSL_CTX_set_post_handshake_auth(SSL_CTX *ctx, int val);
 void SSL_set_post_handshake_auth(SSL *ssl, int val);

الوصف
SSL_CTX_set_verify() تضبط أعلام التحقق لـ ctx لتكون mode وتحدد دالة verify_callback المستخدمة. إذا لم تُحدد دالة رد نداء، يمكن استخدام المؤشر NULL لـ verify_callback. ctx يجب ألا يكون NULL.

SSL_set_verify() تضبط أعلام التحقق لـ ssl لتكون mode وتحدد دالة verify_callback المستخدمة. إذا لم تُحدد دالة رد نداء، يمكن استخدام المؤشر NULL لـ verify_callback. في هذه الحالة، يبقى آخر verify_callback مضبوط خصيصًا لهذا ssl. إذا لم يُضبط callback خاص من قبل، يُستخدم رد النداء المبدئي لـ ctx الأساسي، الذي كان صالحًا وقت إنشاء ssl باستخدام SSL_new(3). داخل دالة رد النداء، يمكن استدعاء SSL_get_ex_data_X509_STORE_CTX_idx للحصول على فهرس بيانات كائن SSL الحالي الذي يقوم بالتحقق.

في وضع العميل، قد تستدعي verify_callback أيضًا دالة SSL_set_retry_verify(3) على كائن SSL المضبوط في البيانات الإضافية x509_store_ctx (انظر SSL_get_ex_data_X509_STORE_CTX_idx(3)) وتُرجع 1. يُفعل هذا عادةً عندما لا يتمكن التحقق من الشهادة من النجاح بعد. يؤدي هذا إلى تعليق المصافحة وإعادة التحكم إلى التطبيق المستدعي مع SSL_ERROR_WANT_RETRY_VERIFY. يمكن للتطبيق، على سبيل المثال، جلب شهادات إضافية أو معلومات حالة الشهادة اللازمة للتحقق. استدعاء SSL_connect(3) مرة أخرى يستأنف محاولة الاتصال بإعادة محاولة خطوة التحقق من شهادة الخادم. قد تُكرر هذه العملية إذا لزم الأمر. لاحظ أن المصافحة قد تُلغى إذا أعاد استدعاء لاحق لرد النداء (مثلًا، على عمق أقل، أو لشرط خطأ منفصل) القيمة 0.

SSL_CTX_set_verify_depth() تضبط أقصى depth للتحقق من سلسلة الشهادات المسموح به لـ ctx.

SSL_set_verify_depth() تضبط أقصى depth للتحقق من سلسلة الشهادات المسموح به لـ ssl.

SSL_CTX_set_post_handshake_auth() و SSL_set_post_handshake_auth() تُفعِّلان إضافة امتداد المصادقة بعد المصافحة إلى ClientHello بحيث يمكن للخادم طلب المصادقة بعد المصافحة. إذا كانت val تساوي 0، لا يُرسل الامتداد، وإلا يُرسل. مبدئيًا، لا يُرسل الامتداد. يجب ضبط رد نداء شهادة عبر SSL_CTX_set_client_cert_cb() إذا لم تُقدم شهادة عند التهيئة.

SSL_verify_client_post_handshake() تُسبب إرسال رسالة طلب شهادة من خادم على اتصال ssl المعطى. يجب ضبط العلم SSL_VERIFY_PEER؛ العلم SSL_VERIFY_POST_HANDSHAKE اختياري.

ملاحظات
يمكن التحكم في التحقق من الشهادات بواسطة مجموعة من أعلام mode المربوطة منطقيًا بـ OR:

SSL_VERIFY_NONE
    وضع الخادم: لن يرسل الخادم طلب شهادة عميل إلى العميل، لذا لن يرسل العميل شهادة.

    وضع العميل: إذا لم يُستخدم مُعمٍّ مجهول (معطل مبدئيًا)، سيرسل الخادم شهادة سيُفحص. يمكن فحص نتيجة عملية التحقق من الشهادة بعد مصافحة TLS/SSL باستخدام دالة SSL_get_verify_result(3). ستستمر المصافحة بغض النظر عن نتيجة التحقق.

SSL_VERIFY_PEER
    وضع الخادم: يرسل الخادم طلب شهادة عميل إلى العميل. تُفحص الشهادة المُعادة (إن وُجدت). إذا فشلت عملية التحقق، تُنهى مصافحة TLS/SSL فورًا برسالة تنبيه تحتوي على سبب فشل التحقق. يمكن التحكم في السلوك بواسطة الأعلام الإضافية SSL_VERIFY_FAIL_IF_NO_PEER_CERT و SSL_VERIFY_CLIENT_ONCE و SSL_VERIFY_POST_HANDSHAKE.

    وضع العميل: تُتحقق شهادة الخادم. إذا فشلت عملية التحقق، تُنهى مصافحة TLS/SSL فورًا برسالة تنبيه تحتوي على سبب فشل التحقق. إذا لم تُرسل شهادة خادم، بسبب استخدام مُعمٍّ مجهول، يُتجاهل SSL_VERIFY_PEER.

SSL_VERIFY_FAIL_IF_NO_PEER_CERT
    وضع الخادم: إذا لم يُعد العميل شهادة، تُنهى مصافحة TLS/SSL فورًا بتنبية "فشل المصافحة". يجب استخدام هذا العلم مع SSL_VERIFY_PEER.

    وضع العميل: تم تجاهله (انظر الأخطاء)

SSL_VERIFY_CLIENT_ONCE
    وضع الخادم: يُطلب شهادة العميل مرة واحدة فقط أثناء الاتصال. لا يُطلب شهادة العميل مرة أخرى أثناء إعادة التفاوض أو ما بعد الاستيثاق إذا طُلبت شهادة أثناء المصافحة الأولية. يجب استخدام هذه العلامة مع SSL_VERIFY_PEER.

    وضع العميل: تم تجاهله (انظر الأخطاء)

SSL_VERIFY_POST_HANDSHAKE
    وضع الخادم: لن يُرسل الخادم طلب شهادة عميل أثناء المصافحة الأولية، بل يُرسل الطلب عبر SSL_verify_client_post_handshake(). يسمح هذا بتكوين SSL_CTX أو SSL للتحقق من النظير بعد المصافحة قبل حدوث المصافحة. يجب استخدام هذه العلامة مع SSL_VERIFY_PEER. TLSv1.3 فقط؛ لا تأثير على اتصالات ما قبل TLSv1.3.

    وضع العميل: تم تجاهله (انظر الأخطاء)

إذا كان الوضع هو SSL_VERIFY_NONE، فلا يجوز تعيين أي من العلامات الأخرى.

إذا لم تُعدّل علامات التحقق صراحةً بواسطة SSL_CTX_set_verify() أو SSL_set_verify()، فستكون القيمة المبدئية هي SSL_VERIFY_NONE.

تُنفذ عملية التحقق الفعلية إما باستخدام إجراء التحقق المدمج أو باستخدام دالة تحقق مقدمة من تطبيق آخر معيّنة مع SSL_CTX_set_cert_verify_callback(3). تنطبق الأوصاف التالية في حالة الإجراء المدمج. كما أن للإجراء المقدم من التطبيق وصول إلى معلومات عمق التحقق ودالة verify_callback()، لكن طريقة استخدام هذه المعلومات قد تكون مختلفة.

SSL_CTX_set_verify_depth() و SSL_set_verify_depth() يضعان حدًا لعدد الشهادات بين شهادات الكيان النهائي ومرساة الثقة. لا تُحتسب شهادات الكيان النهائي ولا مرساة الثقة ضمن العمق. إذا كانت سلسلة الشهادات اللازمة للوصول إلى مُصدر موثوق أطول من العمق+2، فسيُصدر X509_V_ERR_CERT_CHAIN_TOO_LONG. يُحسب العمق كـ "المستوى 0: شهادة النظير"، "المستوى 1: شهادة CA"، "المستوى 2: شهادة CA ذات مستوى أعلى"، وهكذا. تعيين الحد الأقصى للعمق إلى 2 يسمح بالمستويات 0 و1 و2 و3 (0 هو الكيان النهائي و3 هو مرساة الثقة). الحد المبدئي للعمق هو 100، مما يسمح بشهادة النظير، وعلى الأكثر 100 شهادة CA وسيطة وشهادة مرساة ثقة نهائية.

تُستخدم دالة verify_callback للتحكم في السلوك عند تعيين علامة SSL_VERIFY_PEER. يجب أن تُوفر من قبل التطبيق وتستقبل وسيطين: يشير preverify_ok إلى ما إذا كان التحقق من الشهادة المعنية قد نُجح (preverify_ok=1) أم لا (preverify_ok=0). x509_ctx هو مؤشر إلى السياق الكامل المستخدم للتحقق من سلسلة الشهادات.

تُفحص سلسلة الشهادات بدءًا من أعمق مستوى تداخل (شهادة CA الجذرية) وتتجه صعودًا إلى شهادة النظير. في كل مستوى، تُفحص التوقيعات وسمات المُصدر. كلما وُجد خطأ تحقق، يُخزن رقم الخطأ في x509_ctx وتُستدعى verify_callback مع preverify_ok=0. بتطبيق دوال X509_CTX_store_*، يمكن لـ verify_callback تحديد موقع الشهادة المعنية وتنفيذ خطوات إضافية (انظر الأمثلة). إذا لم يُعثر على خطأ لشهادة، تُستدعى verify_callback مع preverify_ok=1 قبل التقدم إلى المستوى التالي.

تتحكم قيمة إرجاع verify_callback في استراتيجية عملية التحقق الإضافية. إذا أعادت verify_callback 0، تتوقف عملية التحقق فورًا مع حالة "فشل التحقق". إذا عُيّنت SSL_VERIFY_PEER، يُرسل تنبيه فشل التحقق إلى النظير وتُنهى مصافحة TLS/SSL. إذا أعادت verify_callback 1، تُستمر عملية التحقق. إذا أعادت verify_callback دائمًا 1، فلن تُنهى مصافحة TLS/SSL بسبب إخفاقات التحقق وسيُؤسس الاتصال. يمكن لعملية الاستدعاء مع ذلك استرداد رمز خطأ آخر خطأ تحقق باستخدام SSL_get_verify_result(3) أو بالحفاظ على مخزن أخطاء خاص بها يُدار بواسطة verify_callback.

إذا لم يُحدد verify_callback، فسيُستخدم الاستدعاء المبدئي. قيمته المرجعة مطابقة لـ preverify_ok، لذا فإن أي فشل تحقق سيؤدي إلى إنهاء مصافحة TLS/SSL مع رسالة تنبيه، إذا عُيّنت SSL_VERIFY_PEER.

بعد استدعاء SSL_set_post_handshake_auth()، سيحتاج العميل إلى إضافة شهادة أو استدعاء شهادة إلى تكوينه قبل أن يتمكن من الاستيثاق بنجاح. يجب استدعاء هذا قبل SSL_connect().

SSL_verify_client_post_handshake() يتطلب أن تكون علامات التحقق قد عُيّنت مسبقًا، وأن العميل قد أرسل امتداد الاستيثاق بعد المصافحة. عندما يُرجع العميل شهادة، سيُستدعى استدعاء التحقق. يجب أن تحدث عملية كتابة لإرسال طلب الشهادة إلى العميل، يمكن القيام بذلك باستخدام SSL_do_handshake() أو SSL_write_ex(). قد يكون طلب شهادة واحد فقط معلقًا في أي وقت.

عند حدوث الاستيثاق بعد المصافحة، تُرسل رسالة NewSessionTicket مُحدّثة إلى العميل.

لا يمكن استخدام الاستيثاق بعد المصافحة مع QUIC. SSL_set_post_handshake_auth() ليس له تأثير إذا استُدعي على كائن SSL من نوع QUIC.

العلل
في وضع العميل، لا يُتحقق مما إذا كانت علامة SSL_VERIFY_PEER معيّنة، بل مما إذا كانت أي علامات غير SSL_VERIFY_NONE معيّنة. قد يؤدي هذا إلى سلوك غير متوقع إذا لم تُستخدم SSL_VERIFY_PEER والعلامات الأخرى كما هو مطلوب.

القيم المُرجعة
لا توفر دوال SSL*_set_verify*() معلومات تشخيصية.

تُرجع دالة SSL_verify_client_post_handshake() 1 إذا نجح الطلب، و0 إذا فشل الطلب. يمكن فحص مكدس الأخطاء لتحديد سبب الفشل.

أمثلة
تُحقق سلسلة التعليمات البرمجية التالية مثالاً لدالة verify_callback ستواصل دائمًا مصافحة TLS/SSL بغض النظر عن فشل التحقق، إذا رُغب. تُحقق الدالة回调 حدًا لعمق التحقق مع مخرجات معلوماتية أكثر.

تُطبع جميع أخطاء التحقق؛ وتُطبع معلومات عن سلسلة الشهادات عند الطلب. يُحقق المثال لخادم يسمح بشهادات العميل لكن لا يطلبها.

يستخدم المثال تقنية ex_data لتخزين بيانات التطبيق في/استرجاع بيانات التطبيق من بنية SSL (انظر CRYPTO_get_ex_new_index(3)، SSL_get_ex_data_X509_STORE_CTX_idx(3)).

 ...
 typedef struct {
   int verbose_mode;
   int verify_depth;
   int always_continue;
 } mydata_t;
 int mydata_index;

 ...
 static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
 {
     char    buf[256];
     X509   *err_cert;
     int     err, depth;
     SSL    *ssl;
     mydata_t *mydata;

     err_cert = X509_STORE_CTX_get_current_cert(ctx);
     err = X509_STORE_CTX_get_error(ctx);
     depth = X509_STORE_CTX_get_error_depth(ctx);

     /*
      * Retrieve the pointer to the SSL of the connection currently treated
      * and the application specific data stored into the SSL object.
      */
     ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
     mydata = SSL_get_ex_data(ssl, mydata_index);

     X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);

     /*
      * Catch a too long certificate chain. The depth limit set using
      * SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
      * that whenever the "depth>verify_depth" condition is met, we
      * have violated the limit and want to log this error condition.
      * We must do it here, because the CHAIN_TOO_LONG error would not
      * be found explicitly; only errors introduced by cutting off the
      * additional certificates would be logged.
      */
     if (depth > mydata->verify_depth) {
         preverify_ok = 0;
         err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
         X509_STORE_CTX_set_error(ctx, err);
     }
     if (!preverify_ok) {
         printf("verify error:num=%d:%s:depth=%d:%s\n", err,
                X509_verify_cert_error_string(err), depth, buf);
     } else if (mydata->verbose_mode) {
         printf("depth=%d:%s\n", depth, buf);
     }

     /*
      * At this point, err contains the last verification error. We can use
      * it for something special
      */
     if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) {
         X509_NAME_oneline(X509_get_issuer_name(err_cert), buf, 256);
         printf("issuer= %s\n", buf);
     }

     if (mydata->always_continue)
         return 1;
     else
         return preverify_ok;
 }
 ...

 mydata_t mydata;

 ...
 mydata_index = SSL_get_ex_new_index(0, "mydata index", NULL, NULL, NULL);

 ...
 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE,
                    verify_callback);

 /*
  * Let the verify_callback catch the verify_depth error so that we get
  * an appropriate error in the logfile.
  */
 SSL_CTX_set_verify_depth(verify_depth + 1);

 /*
  * Set up the SSL specific data into "mydata" and store it into th SSL
  * structure.
  */
 mydata.verify_depth = verify_depth; ...
 SSL_set_ex_data(ssl, mydata_index, &mydata);

 ...
 SSL_accept(ssl);       /* check of success left out for clarity */
 if (peer = SSL_get_peer_certificate(ssl)) {
     if (SSL_get_verify_result(ssl) == X509_V_OK) {
         /* The client sent a certificate which verified OK */
     }
 }

انظر أيضًا
ssl(7)، SSL_new(3)، SSL_CTX_get_verify_mode(3)، SSL_get_verify_result(3)، SSL_CTX_load_verify_locations(3)، SSL_get_peer_certificate(3)، SSL_CTX_set_cert_verify_callback(3)، SSL_get_ex_data_X509_STORE_CTX_idx(3)، SSL_CTX_set_client_cert_cb(3)، CRYPTO_get_ex_new_index(3)

التاريخ
خيار SSL_VERIFY_POST_HANDSHAKE، والدالتان SSL_verify_client_post_handshake() و SSL_set_post_handshake_auth() أُضيفتا في OpenSSL 1.1.1.

حقوق النسخ
حقوق النشر 2000-2024 لمؤلفي مشروع OpenSSL. جميع الحقوق محفوظة.

مرخص بموجب رخصة Apache 2.0 (المشار إليها فيما يلي بـ ”الرخصة“). لا يجوز لك استخدام هذا الملف إلا وفقًا لشروط الرخصة. يمكنك الحصول على نسخة منها في الملف LICENSE الموجود في حزمة التوزيع المصدرية أو على الرابط <https://www.openssl.org/source/license.html>.

ترجمة
تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 (https://www.gnu.org/licenses/gpl-3.0.html) أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.