Взаимный SSL с использованием: моно, C # и самоподписанных сертификатов - PullRequest
2 голосов
/ 15 апреля 2019

Вот проект: я создаю TcpListener в C #, который будет размещаться на Linux-боксе с использованием Mono.

Тогда у меня будет TcpClient (также Mono в Linux), который будет подключаться к нему, и, поскольку у меня не может быть аутентификация имени пользователя / пароля, мне бы хотелось, чтобы клиенты подключались с помощью «сертификата клиента»., который я сгенерирую с помощью своего корневого центра сертификации (также самогенерируемого)

У меня не может быть только безопасное подключение клиента к серверу, мне нужен мой TcpListener, чтобы также доверять моему клиентскому соединению.1006 * Что я сделал до сих пор: я экспортировал свой сертификат сервера как PFX:

и загрузил его в код:

sslCertificate = new X509Certificate2("myCert.pfx", "password");

Теперь, если я запустил код, как показано ниже:

bool requireClientCertificate = false; // <== turn on/off
SslStream sslStream = new SslStream(netStream, false, new RemoteCertificateValidationCallback(AcceptRemoteCertificate));
sslStream.AuthenticateAsServer(sslCertificate, requireClientCertificate, SslProtocols.Tls, false);

С requireClientCertificate = false, тогда я могу использовать браузер для просмотра этой страницы совершенно нормально.Конечно, я бы уже импортировал свой Root CA, чтобы увидеть эту страницу, иначе Chrome выдаст мне предупреждение с сертификатом.

Правильно, так что проблем с этим пока нет ... и SSLустановлено, но технически любой мог подключиться к этому TcpListner.

Теперь я установил requireClientCertificate = true, и это то, где все разваливается.

Я понимаю, что мне нужно сгенерировать сертификат клиента, поэтому я сделал это, экспортировал его и импортировал на свой компьютер.Я вижу его в списке сертификатов в Chrome, и мне предлагается использовать его, когда я впервые пытаюсь подключить TcpListner.

Однако, делая все это, по-прежнему ничего не решается.

Я также установил Root CA на сервер, используя:

  1. скопировать в /usr/share/ca-certificates/mozilla/MyRootCA.crt
  2. редактирование/etc/ca-certificates.conf
  3. update-ca-сертификаты (Это показывает, 1 установлен новый сертификат .. но все равно не помогло)

Затем я попытался: certmgr -add -c -v -m Trust /home/Certs/MyRootCA.crt Все еще не работает, поэтому я попытался: certmgr -add -c -v -m CA /home/Certs/MyRootCA.crt

Итак, из того, что я вижу, установлен RootCA.

Если я пытаюсь подключиться к Chrome, я получаю: RemoteCertificateChainErrors inRemoteCertificateValidationCallback

И если я зациклился на цепочке, я получил: PartialChain в Информации о состоянии.

И если я тестирую с OpenSSL, я получу: RemoteCertificateChainErrors с:UntrustedRoot в информации о состоянии

Совершенно запутанная часть этого заключается в том, что мой RemoteCertificate от TcpListner не имеет значения null - это фактически сертификат, который я установил в браузере, и он может видетьRootCA, который подписал его тоже (Эмитент).

Если я на самом деле делаю: wget https://api.myserver.com --certificate=/my.crt --private-key=/my.key --ca-certificate=/MyRootCA.crt, он подключается и загружает мои ускоренные результаты.

Итак, вопросы:

  1. На самом ли деле это соединение взаимно защищено?
  2. О чем эти ошибки? UntrustedRoot и PartialChain
  3. Если он имеет эти ошибки, но все еще может представлять RemoteCertificate, означает ли это его взаимно защищенное соединение или нет?

В прошлом я делал это на Windows Server с коммерческими сертификатами CA (DigiCert EV) и другими (вне моего контроля) CPE, и они работали без ошибок.Это единственное отличие, которое я заметил.Это причина?Есть ли у Linux / Mono какие-то дополнительные знания о сертификатах, что если вы создаете свой собственный корневой центр сертификации ... он не может полностью ему доверять?

РЕДАКТИРОВАТЬ:

Я не получил полного ответа, но обнаружил несколько вещей.Был бы очень признателен за помощь от кого-то, кто имеет эту работу.

Итак, я обнаружил, что вы можете проверить свойства потока (ssl) .IsMutuallyAuthenticated и .IsSigned и .IsEncrypted.Это жизненно важно для этого, и особенно .IsMutuallyAuthenticated.

Как оказалось, манипулируя ответом RemoteCertificateValidationCallback true / false, вы можете обрабатывать ошибки, которые вы «не возражаете», и отклонять другие.В этом случае соединение разрывается и возникает ошибка.Однако в моих RemoteCertificateChainErrors мне удалось вернуть значение true ... и при этом stream.IsMutuallyAuthenticated возвращалось значение True!Yay

Хорошо, теперь я собираю клиента с:

HttpWebRequest requestObj = (HttpWebRequest)WebRequest.Create(strURL);
requestObj.ClientCertificates = certs;

Это представляет сертификаты для моего кода сервера, и теперь это то, где его интересно ... После получения объекта ответа:

HttpWebResponse responseObj = (HttpWebResponse)requestObj.GetResponse();
Debug.WriteLine("IsMutuallyAuthenticated: " + responseObj.IsMutuallyAuthenticated);

Даже если я получаю ожидаемые результаты, а responseObj.StatusCode == HttpStatusCode.OK, IsMutuallyAuthenticated неверно. Ясно, что это проблема с сертификатом, который я представляю на стороне клиента.

Кажется, что код на стороне клиента НЕ ДОЛЖЕН доверять сертификату, который он представляет, но я установил Root CA локально на ПК. И Локальная Машина, и Пользователь. Если я открою магазин - и перечислю сертификаты, его там.

Кажется, это сложнее, чем должно быть. Любая помощь поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...