سؤال

أحتاج إلى توفير اتصال آمن بين العمليات المختلفة التي تستخدم مآخذ توصيل TCP/IP للاتصال.أريد كلا من المصادقة والتشفير.بدلاً من إعادة اختراع العجلة، أود حقًا استخدام SSL وفئة SslStream والشهادات الموقعة ذاتيًا.ما أريد القيام به هو التحقق من صحة شهادة العملية عن بعد مقابل نسخة معروفة في تطبيقي المحلي.(ليست هناك حاجة إلى مرجع مصدق لأنني أنوي نسخ الشهادات يدويًا).

وللقيام بذلك، أريد أن يكون التطبيق قادرًا على إنشاء شهادة جديدة تلقائيًا في المرة الأولى التي يتم تشغيله فيها.بالإضافة إلى makecert.exe، يبدو هذا الرابط يعرض طريقة لإنشاء شهادات موقعة ذاتيًا تلقائيًا، وهذه هي البداية.

لقد ألقيت نظرة على طريقتي AuthenticateAsServer وAuthenticateAsClient في SslStream.يمكنك تقديم معاودة الاتصال للتحقق، لذلك يبدو أن ذلك ممكنًا.لكن الآن بعد أن دخلت في تفاصيل الأمر، لا أعتقد حقًا أنه من الممكن القيام بذلك.

هل أنا أسير في الاتجاه الصحيح؟هل هناك بديل أفضل؟هل قام أي شخص بشيء مثل هذا من قبل (بشكل أساسي SSL من نظير إلى نظير بدلاً من خادم العميل)؟

هل كانت مفيدة؟

المحلول

الخطوة 1: إنشاء شهادة موقعة ذاتيًا:

  • لقد قمت بتحميل فئة الشهادة.cs تم النشر بواسطة دوج كوك
  • لقد استخدمت هذا الرمز لإنشاء ملف شهادة .pfx:

    byte[] c = Certificate.CreateSelfSignCertificatePfx(
            "CN=yourhostname.com", //host name
            DateTime.Parse("2000-01-01"), //not valid before
            DateTime.Parse("2010-01-01"), //not valid after
            "mypassword"); //password to encrypt key file
    
        using (BinaryWriter binWriter = new BinaryWriter(
            File.Open(@"testcert.pfx", FileMode.Create)))
        {
            binWriter.Write(c);
        }
    

الخطوة 2: تحميل الشهادة

    X509Certificate cert = new X509Certificate2(
                            @"testcert.pfx", 
                            "mypassword");

الخطوه 3: تجميعها معًا

  • لقد استندت إليه هذا مثال SslStream البسيط جدًا
  • سوف تحصل على خطأ وقت الترجمة حول تعداد SslProtocolType.فقط قم بتغيير ذلك من SslProtocolType.Default إلى SslProtocols.Default
  • كانت هناك 3 تحذيرات حول الوظائف المهملة.لقد استبدلتهم جميعًا بالبدائل المقترحة.
  • لقد استبدلت هذا السطر في ملف Server Program.cs بالسطر من الخطوة 2:

    X509Certificate cert = getServerCert();

  • في ملف Client Program.cs، تأكد من تعيين serverName = yourhostname.com (وأنه يطابق الاسم الموجود في الشهادة)

  • في Client Program.cs، تفشل وظيفة CertifiedValidationCallback لأن sslPolicyErrors يحتوي على RemoteCertificateChainErrors.إذا تعمقت قليلاً، فذلك لأن الجهة المصدرة التي وقعت الشهادة ليست جذرًا موثوقًا به.
  • لا أريد الخوض في مسألة قيام المستخدم باستيراد الشهادات إلى المتجر الجذر، وما إلى ذلك، لذلك قدمت حالة خاصة لهذا الأمر، وتحققت من أن الشهادة.GetPublicKeyString() مساوية للمفتاح العام الموجود لدي في الملف لهذا الخادم.إذا تطابقت، سأرجع True من تلك الدالة.يبدو أن هذا يعمل.

الخطوة 4: مصادقة العميل

إليك كيفية مصادقة عميلي (إنها مختلفة قليلاً عن الخادم):

TcpClient client = new TcpClient();
client.Connect(hostName, port);

SslStream sslStream = new SslStream(client.GetStream(), false,
    new RemoteCertificateValidationCallback(CertificateValidationCallback),
    new LocalCertificateSelectionCallback(CertificateSelectionCallback));

bool authenticationPassed = true;
try
{
    string serverName = System.Environment.MachineName;

    X509Certificate cert = GetServerCert(SERVER_CERT_FILENAME, SERVER_CERT_PASSWORD);
    X509CertificateCollection certs = new X509CertificateCollection();
    certs.Add(cert);

    sslStream.AuthenticateAsClient(
        serverName,
        certs,
        SslProtocols.Default,
        false); // check cert revokation
}
catch (AuthenticationException)
{
    authenticationPassed = false;
}
if (authenticationPassed)
{
    //do stuff
}

إن CertifiedValidationCallback هو نفسه الموجود في حالة الخادم، ولكن لاحظ كيف يأخذ AuthenticateAsClient مجموعة من الشهادات، وليس شهادة واحدة فقط.لذلك، يجب عليك إضافة LocalCertificateSelectionCallback، مثل هذا (في هذه الحالة، لدي شهادة عميل واحدة فقط لذلك أقوم فقط بإرجاع الشهادة الأولى في المجموعة):

static X509Certificate CertificateSelectionCallback(object sender,
    string targetHost,
    X509CertificateCollection localCertificates,
    X509Certificate remoteCertificate,
    string[] acceptableIssuers)
{
    return localCertificates[0];
}

نصائح أخرى

ويمكنك أن تبحث أيضا هذا المثال عينة العميل غير متزامن SslStream / تنفيذ الخادم HTTP: // blogs.msdn.com/joncole/archive/2007/06/13/sample-asynchronous-sslstream-client-server-implementation.aspx

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

وشهادة سبيل المثال الأساسي

وmakecert -sr LocalMachine -SS بلدي -n CN = اختبار الصرف -sky -sk 123456

أو

وفي ملف خارجي

وmakecert -sr LocalMachine -SS بلدي -n CN = اختبار الصرف -sky -sk 123456 ج: \ Test.cer

وشهادة أداة الخلق (Makecert.exe)
http://msdn.microsoft.com/en- لنا / مكتبة / bfsktky3٪ 28VS.80٪ 29.aspx

وماذا كنت اقتراح يبدو على ما يرام بالنسبة لي، إلا أنه يبدو وكأنه كنت تبحث الانتظار حتى يتم استدعاء رد الاتصال من أجل توليد الشهادة. أنا لا أعتقد أن ذلك سوف يطير. AFAIK، كنت قد حصلت على تقديم شهادة صالحة عند استدعاء AuthenticateAsX.

ولكن هذه الطبقات هي للتجاوز. حتى من الناحية النظرية، يمكنك إنشاء فئة مشتقة الذي الشيكات الأولى لمعرفة ما إذا كان شهادة يتعين توليدها، ويولد ذلك إذا لزم الأمر، ثم استدعاء الأسلوب AuthenticateAsX الأم.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top