SSL через TCP Проверка подлинности службы Windows с помощью сертификата

У меня есть один сервер и три клиента, на которых служба Windows работает с правами локальной системы. Клиенты и сервер проходят взаимную аутентификацию с использованием SSL через TCP и сертификатов (я использую класс SSLStream C++\CLI http://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.90).aspx#Y1124)

Проблема в том, что мне нужно три сертификата (по одному на каждого клиента), потому что я аутентифицирую хосты. Теперь я хочу аутентифицировать службу Windows, а не хост, чтобы я мог распространять один и тот же сертификат для каждого хоста.

Кто-нибудь знает, как это можно сделать?

--- РЕДАКТИРОВАТЬ 1 ---- Чтобы дать вам пример того, что я хочу сделать. В каждой копии Microsoft Office развернут сертификат, который используется для связи с серверами Microsoft по зашифрованному каналу с проверкой подлинности.

-- РЕШЕНО--

Как сказал Джон, моя проблема заключалась в том, что класс SslStream выполняет стандартную проверку, которая включает имя хоста. Я предоставил собственный RemoteCertificateValidationCallback, и теперь он работает.

bool ValidateServerCertificate( Object^ sender, X509Certificate^ certificate, X509Chain^ chain, SslPolicyErrors sslPolicyErrors ) {            

  Console::Write("[+] Validating server certificate: ");                                 

  // check certificate hash                                                               
  if( certificate->GetCertHashString()->Equals("cert hash") ) {                                                                                                          
      Console::Write( "oK\n" );                                                      
      return true;                                                                   
  }                                                                                      

   Console::Write(" ERROR\n");                  
   Console::WriteLine("[-] Hash doesn't match");                                 

   // Do not allow this client to communicate with unauthenticated servers.                           
   return false;                                                                                                                                                                                                  
} 

person DropTheCode    schedule 17.01.2012    source источник
comment
И клиенты, и сервер находятся в одном домене Windows? Доступ к серверу осуществляется через Интернет?   -  person Dmitry Shkuropatsky    schedule 17.01.2012
comment
Нет, они не находятся в одном домене, и да, доступ к серверу осуществляется через Интернет.   -  person DropTheCode    schedule 17.01.2012
comment
Итак, что вы хотите, так это развернуть один и тот же сертификат на всех трех хостах и ​​использовать его для аутентификации? Как вы хотите его развернуть? .pfx файл?   -  person Jon    schedule 17.01.2012
comment
Да, файл .pfx и используйте его для аутентификации службы Windows, чтобы у меня был один и тот же сертификат на каждом хосте.   -  person DropTheCode    schedule 17.01.2012
comment
Мне нужна взаимная аутентификация, поэтому обе стороны должны быть аутентифицированы.   -  person DropTheCode    schedule 17.01.2012
comment
Не могли бы вы уточнить отношения между сущностями в вашем вопросе? Я имею в виду, служба Windows означает клиентское или серверное приложение? Хост означает клиентское или серверное приложение?   -  person Dmitry Shkuropatsky    schedule 19.01.2012


Ответы (1)


Вам просто нужно загрузить сертификат, например. из файла и использовать этот конкретный сертификат для аутентификации. Если вы хотите сделать это на стороне сервера соединения:

var certificate = new X509Certificate2("cert.pfx");
sslStream.AuthenticateAsServer(certificate);

И на стороне клиента:

X509Certificate certificate = new X509Certificate2("cert.pfx");
var certCollection = new X509CertificateCollection(new[] { certificate });
sslStream.AuthenticateAsClient(targetHost, certCollection, protocols, checkRevocation);

Если сертификаты находятся в файлах, защищенных паролем, есть второй параметр для X509Certificate2 конструктор, который принимает пароль. И, конечно же, вы, вероятно, захотите использовать разные сертификаты для клиентов и сервера.

Обновление:

Таким образом, кажется, что ваша проблема заключается в том, что ваши сертификаты не принимаются, потому что вы позволяете .NET выполнять стандартную проверку (включая проверку хоста). Вам просто нужно предоставить RemoteCertificateValidationCallback вашему SslStream конструктор. Затем вы можете сделать все проверки, которые хотите (или нет) внутри этого. Например, вот валидатор, который слепо примет любой сертификат:

private bool DefaultCertificateValidationHandler(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors)
{
    return true;
}
person Jon    schedule 17.01.2012
comment
Но насколько я знаю, поле SUBJECT сертификата x509 должно быть именем хоста/веб-сайта. Я должен аутентифицировать службу Windows, а не хост. - person DropTheCode; 17.01.2012
comment
@drop: просмотрите обновление, но, пожалуйста, предоставьте всю соответствующую информацию заранее (например, какова общая картина, что вы сделали и что именно вызывает у вас проблемы). - person Jon; 17.01.2012
comment
Спасибо за помощь, но, возможно, вы не понимаете моей проблемы. У меня есть 1 сервер и 3 клиента, на каждом клиенте запущена служба Windows. Цель этой службы Windows — подключиться к серверу и обменяться некоторыми сообщениями. Эта связь должна быть зашифрована и аутентифицирована (обе стороны). Для этого я использовал класс SSLStream и сертификат .pfx (x509). Он отлично работает, но для каждого клиента мне нужен другой сертификат. Я хочу использовать только 1 сертификат для всех клиентов, для этого я думаю, что мне нужно аутентифицировать службу Windows, а НЕ хост. - person DropTheCode; 17.01.2012
comment
@drop: используйте приведенный выше код, чтобы контролировать процесс проверки сертификата. Думаю, я получил эту часть. - person Jon; 17.01.2012
comment
Да, но этот сертификат аутентифицирует только одного клиента, потому что, когда я создаю сертификат с помощью команды makecert -r -pe -n "**CN=HOST NAME**" -sky exchange ...., поле CN уникально для этого хоста. Я не могу установить этот сертификат на другом хосте. - person DropTheCode; 17.01.2012
comment
@drop: я успешно использовал эту технику для написания переносимого клиент-серверного приложения с SSL, поэтому я знаю, что это работает. Я могу только догадываться, с какими проблемами вы столкнулись. Но вам не нужно устанавливать сертификат. - person Jon; 17.01.2012
comment
Когда вы создали сертификат, какое имя вы указали в поле CN? - person DropTheCode; 17.01.2012
comment
CN=server.whatever.com -- это не имеет никакого значения, потому что вы не собираетесь проверять сертификат на основе этого. - person Jon; 17.01.2012
comment
Уверены ли вы ? Потому что на странице википедии на x509 написано: Его тема содержит много личных данных, но наиболее важной частью обычно является общее имя (CN), поскольку это часть, которая должна соответствовать аутентифицируемому хосту. Таким образом, я не могу установить CN со случайным именем. - person DropTheCode; 18.01.2012
comment
На самом деле, если я устанавливаю случайное имя (CN = abc), я получаю эту ошибку: RemoteCertificateNameMismatch. - person DropTheCode; 18.01.2012