Использование SSL и SslStream для одноранговой аутентификации?
Мне нужно обеспечить безопасную связь между различными процессами, которые используют сокеты TCP/IP для связи. Мне нужны и аутентификация, и шифрование. Вместо того, чтобы заново изобретать колесо, я бы очень хотел использовать SSL и класс SslStream и самозаверяющие сертификаты. Я хочу проверить сертификат удаленного процесса на соответствие известной копии в моем локальном приложении. (Нет необходимости в центре сертификации, потому что я намерен, чтобы сертификаты были скопировано вручную).
для этого я хочу, чтобы приложение могло автоматически генерировать новый сертификат при первом запуске. В дополнение к этим инструментом.exe, это выглядит как этой ссылке показывает способ автоматического создания самозаверяющих сертификатов, так что это начало.
Я посмотрел на AuthenticateAsServer и AuthenticateAsClient методы SslStream. Вы можете предоставить обратные вызовы для проверки, поэтому похоже, что это возможно. Но теперь, когда я в деталях, я действительно не думаю, что это возможно.
Я иду в правильном направлении? Есть ли лучшая альтернатива? Кто-нибудь делал что-то подобное раньше (в основном одноранговый SSL, а не клиент-сервер)?
3 ответов
Шаг 1: создание самозаверяющего сертификата:
- Я скачал сертификаты.класс 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.По умолчанию используется SslProtocols.По умолчанию
- было 3 предупреждения об устаревших функциях. Я заменил их предлагаемыми заменами.
-
Я заменил эту строку в программе сервера.cs файл со строкой из шага 2:
X509Certificate cert = getServerCert ();
In клиентская программа.cs-файл, убедитесь, что вы установили имя_сервера = yourhostname.com (и что он соответствует имени в сертификате)
- в клиентской программе.cs, функция CertificateValidationCallback завершается ошибкой, поскольку sslPolicyErrors содержит RemoteCertificateChainErrors. Если вы копнете немного глубже, это связано с тем, что центр выдачи, подписавший сертификат, не является доверенным корнем.
- Я не хочу, чтобы пользователь импортировал сертификаты в магазин корня, etc., поэтому я сделал особый случай для этого, и я проверяю этот сертификат.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];
}
вы можете посмотреть тоже этот пример Пример Асинхронной Реализации SslStream Клиент / Сервер http://blogs.msdn.com/joncole/archive/2007/06/13/sample-asynchronous-sslstream-client-server-implementation.aspx
Если сертификат не создан правильно, вы можете получить исключение режим сервера SSL должен использовать сертификат с соответствующим закрытым ключом.
простой пример сертификата
makecert-sr LocalMachine-ss My-N CN=тест-небо exchange-sk 123456
или
как внешним файлом
makecert-sr LocalMachine-ss My-N CN=тест-sky exchange-sk 123456 c:\Test - ... cer
Инструмент Создания Сертификата (Makecert.exe)
http://msdn.microsoft.com/en-us/library/bfsktky3%28VS.80%29.aspx
то, что вы предлагаете, звучит хорошо для меня, за исключением того, что похоже, что вы хотите подождать, пока обратный вызов не будет вызван для создания сертификата. Я не думаю, что это будет летать; AFAIK, вы должны предоставить действительный сертификат при вызове AuthenticateAsX
.
однако эти классы переопределяемы; поэтому теоретически вы можете создать производный класс, который сначала проверяет, должен ли быть создан сертификат, генерирует его, если это необходимо, а затем вызывает Родительский AuthenticateAsX
метод.