Вот проект: я создаю 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 на сервер, используя:
- скопировать в /usr/share/ca-certificates/mozilla/MyRootCA.crt
- редактирование/etc/ca-certificates.conf
- 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
, он подключается и загружает мои ускоренные результаты.
Итак, вопросы:
- На самом ли деле это соединение взаимно защищено?
- О чем эти ошибки? UntrustedRoot и PartialChain
- Если он имеет эти ошибки, но все еще может представлять 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 локально на ПК. И Локальная Машина, и Пользователь. Если я открою магазин - и перечислю сертификаты, его там.
Кажется, это сложнее, чем должно быть. Любая помощь поможет.