这是项目: 我正在用C#创建一个TcpListener,它将使用Mono在Linux盒子上托管。
然后,我将有一个TcpClient(在Linux上也为Mono)将与其连接,并且由于我无法使用用户名/密码进行身份验证,因此我希望客户端使用“客户端证书”进行连接,将通过我的根CA生成(也是自生成的)
我不仅可以让客户端安全地连接到服务器,还需要我的TcpListener信任我的客户端连接。
到目前为止我做了什么: 我已将服务器证书导出为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
,我可以使用浏览器完美浏览此页面。当然,为了查看该页面,我已经导入了我的根CA,否则Chrome会向我发出证书警告。
对,所以到目前为止,这没有问题...并且SSL已建立,但是从技术上讲,任何人都可以连接到此TcpListner。
现在,我设置requireClientCertificate = true
,这是事情分崩离析的地方。
我意识到我需要生成一个客户端证书,所以我做到了,将其导出,然后将其导入到我的PC中。我可以在Chrome的证书列表下看到它,当我第一次尝试连接TcpListner时,系统会提示我使用它。
尽管如此,仍然不能解决问题。
我还使用以下方法在服务器上安装了根CA:
然后我尝试了:
certmgr -add -c -v -m Trust /home/Certs/MyRootCA.crt
仍然无法正常工作,所以我尝试了:
certmgr -add -c -v -m CA /home/Certs/MyRootCA.crt
所以从我可以看到RootCA已安装。
如果我尝试连接Chrome,则会得到:
RemoteCertificateChainErrors
RemoteCertificateValidationCallback
如果我不停地想着链条,我会在状态信息中得到PartialChain
。
如果我使用OpenSSL进行测试,则会得到:
RemoteCertificateChainErrors
,其中:状态信息中的UntrustedRoot
对此,最令人困惑的部分是,我的TcpListner的RemoteCertificate不为空-实际上,这是我在浏览器上安装的证书,并且可以看到也为它颁发证书的RootCA(发行人)。 / p>
如果我确实执行了以下操作:wget https://api.myserver.com --certificate=/my.crt --private-key=/my.key --ca-certificate=/MyRootCA.crt
,它会连接并下载我的快速结果。
所以,问题:
过去,我是在Windows Server上使用商业CA证书(DigiCert E.V.)和其他(不受我控制的)CPE来完成此操作的,它们可以正常工作。这是我注意到的唯一区别。这是原因吗? Linux / Mono是否具有有关证书的某种其他知识,如果您生成自己的Root CA ...它将无法完全信任它?
编辑:
我没有一个完整的答案,但是我发现了一些东西。真的很感谢有这项工作的人的帮助。
所以我发现您可以检查.IsMutuallyAuthenticated
和.IsSigned
和.IsEncrypted
的流(ssl)属性。这一点至关重要,尤其是.IsMutuallyAuthenticated
。
事实证明,通过操纵RemoteCertificateValidationCallback
响应的是非,您可以处理“不介意”的错误,并拒绝其他错误。在这种情况下,连接断开,并引发错误。但是,在我的 RemoteCertificateChainErrors 中,我能够返回true ...,而当做stream.IsMutuallyAuthenticated
时,它返回True!是的
好的,现在我用:
HttpWebRequest requestObj = (HttpWebRequest)WebRequest.Create(strURL);
requestObj.ClientCertificates = certs;
这将证书提供给我的服务器代码,现在这是它有趣的地方...获得响应对象之后:
HttpWebResponse responseObj = (HttpWebResponse)requestObj.GetResponse();
Debug.WriteLine("IsMutuallyAuthenticated: " + responseObj.IsMutuallyAuthenticated);
即使我得到了预期的结果,并且responseObj.StatusCode == HttpStatusCode.OK
,IsMutuallyAuthenticated
是错误的。很明显,这是我要向客户端提供的证书的问题。
似乎客户端代码不能信任它所提供的证书,但是我已经在PC上本地安装了根CA。本地计算机和用户。如果我开了商店-并列出了证书,则在那里。
这似乎比应做的要困难。任何帮助都会有所帮助。