Как использовать сертификаты X.509?
Допустим я хочу написать 2 консольные программы: клиент и сервер. Создам самоподписанные сертификаты, установлю их на машинах клиента(тут в доверенные .cer) и сервера(тут с приватным ключем .pfx). Использую c#.
Как связать мой сервер-консоль с сертификатом? Похоже что в веб серверах(IIS к примеру) есть возможность установить сертификат, то есть это привязка серверного приложения к конкретному сертификату. Как без веб сервера связать сертификат с программой? Нужно ли в коде приложения как-то учитывать то что это будет https?
Как проверять сертификат на клиент-консоле? Слышал что в браузерах эта логика прописана. Вытащить программно сертификаты из хранилища и прописать логику сравнения с тем который приходит с сервера самому или связать программы с сертификатами можно через cmd и OS сама все проверит?
Ответы (2 шт):
Протокол TLS в .NET реализован классом System.Net.Security.SslStream. Этот класс реализует и клиентскую сторону, и серверную.
Подробнейший пример есть в MSDN
В этом примере серверный сертификат используется в вызове метода SslStream.AuthenticateAsServer:
sslStream.AuthenticateAsServer(serverCertificate, clientCertificateRequired: false, checkCertificateRevocation: true);
В примере путь к файлу сертификата передается как параметр командной строки. Сертификаты в .NET представляются классами System.Security.Cryptography.X509Certificates.X509Certificate (используется в примере) и System.Security.Cryptography.X509Certificates.X509Certificate2 (рекомендуется Майкрософтом).
В примере из MSDN сертификат конструируется статическим методом X509Certificate.CreateFromCertFile.
Клиент устанавливает защищенное соединение с сервером вызовом метода SslStream.AuthenticateAsClient. Этот метод проверяет сертификат сервера и согласовывает параметры защищенного соединения.
Проверка серверного сертификата состоит из двух этапов. Сначала внутренние классы .NET парсят сертификат(ы), присланные сервером и проверяют на базовые ошибки - корректный синтаксис, время NotValidBefore/NotValidAfter, Purpose, целостность цепочки сертификатов, соответствие имени сервера имени в сертификате (имя сервера передаётся как аргумент в AuthenticateAsClient). Затем вызывается делегат типа RemoteCertificateValidationCallback, который передаётся как аргумент конструктора клиентского потока SslStream. В примере клиента, ссылку на который я привел в начале, используется тривиальный коллбэк. Он останавливает аутентификацию, если при проверке серверного сертификата обнаружены какие-либо ошибки.
Защищенное соединение по протоколу TLS устанавливается после того, как на серверной стороне отработает метод AuthenticateAsServer, а на клиентской стороне AuthenticateAsClient.
Класс SslStream предоставляет интерфейс типа Stream. Для отправки данных используется метод SslStream.Write, а для получения - SslStream.Read. Всё шифрование/расшифрование и, при необходимости, переустановка соединения, происходят прозрачным образом внутри SslStream.
Недавно появился пост который отвечает на эти вопросы https://habr.com/ru/post/581740/