Использование SSL и SslStream для одноранговой аутентификации?

Мне нужно обеспечить безопасную связь между различными процессами, использующими сокеты TCP / IP для связи. Я хочу как аутентификацию, так и шифрование. Вместо того, чтобы изобретать колесо, я бы очень хотел использовать SSL и class SslStream и самозаверяющие сертификаты. То, что я хочу сделать, – проверить сертификат удаленного процесса на известную копию в моем локальном приложении. (Вам не обязательно быть центром сертификации, потому что я намерен копировать сертификаты вручную).

Для этого я хочу, чтобы приложение могло автоматически генерировать новый сертификат при первом запуске. В дополнение к makecert.exe, похоже, эта ссылка показывает способ автоматического создания самозаверяющих сертификатов, так что это начало.

Я просмотрел методы AuthenticateAsServer и AuthenticateAsClient для SslStream. Вы можете предоставить обратные вызовы для проверки, поэтому похоже, что это возможно. Но теперь, когда я подробно расскажу об этом, я действительно не думаю, что это возможно.

Я иду в правильном направлении? Есть ли лучшая альтернатива? Кто-нибудь сделал что-нибудь подобное раньше (в основном одноранговый SSL, а не клиент-сервер)?

    Шаг 1: Создание самозаверяющего сертификата:

    • Я загрузил class Certificate.cs, опубликованный Doug Cook
    • Я использовал этот код для создания файла сертификата .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 функция CertificateValidationCallback не работает, потому что sslPolicyErrors содержит RemoteCertificateChainErrors. Если вы копаете немного глубже, это происходит потому, что выдающий орган, который подписал сертификат, не является доверенным корнем.
    • Я не хочу, чтобы пользователь импортировал сертификаты в корневой магазин и т. Д., Поэтому я сделал для этого специальный случай, и я проверяю, что certificate.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 } 

    CertificateValidationCallback такой же, как в случае сервера, но обратите внимание, как AuthenticateAsClient берет коллекцию сертификатов, а не только один сертификат. Итак, вам нужно добавить LocalCertificateSelectionCallback, как это (в этом случае у меня есть только один клиентский сертификат, поэтому я просто возвращаю первый в коллекции):

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

    вы можете также посмотреть этот пример. Пример внедрения Asynchronous SslStream Client / Server http://blogs.msdn.com/joncole/archive/2007/06/13/sample-asynchronous-sslstream-client-server-implementation.aspx

    если сертификат не создан правильно, вы можете получить исключение. Режим сервера SSL должен использовать сертификат с соответствующим закрытым ключом.

    пример базового сертификата

    makecert -sr LocalMachine -ss My -n CN = Test -sky exchange -sk 123456

    или

    как внешний файл

    makecert -sr LocalMachine -ss My -n CN = Test -sky exchange -sk 123456 c: \ Test.cer

    Инструмент создания сертификата (файл Makecert.exe)
    http://msdn.microsoft.com/en-us/library/bfsktky3%28VS.80%29.aspx

    То, что вы предлагаете, отлично подходит для меня, за исключением того, что кажется, что вы хотите подождать, пока обратный вызов не будет вызван для создания сертификата. Я не думаю, что это будет летать; AFAIK, вы должны предоставить действительный сертификат при вызове AuthenticateAsX .

    Однако эти classы являются сверхъестественными; так что теоретически вы можете создать производный class, который сначала проверяет, нужно ли генерировать сертификат, генерирует его, если необходимо, затем вызывает родительский метод AuthenticateAsX .

    Давайте будем гением компьютера.