使用以下方式的相互SSL:Mono,C#和自签名证书

时间:2019-04-15 07:51:16

标签: c# ssl mono

这是项目: 我正在用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:

  1. 复制到/usr/share/ca-certificates/mozilla/MyRootCA.crt
  2. 编辑/etc/ca-certificates.conf
  3. update-ca-certificates (这显示已安装1个新证书。但是仍然没有帮助)

然后我尝试了: 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,它会连接并下载我的快速结果。

所以,问题:

  1. 此连接实际上相互安全吗?
  2. 这些错误是关于什么的? UntrustedRoot PartialChain
  3. 如果出现这些错误,但仍然可以显示RemoteCertificate,这是否意味着它是一个相互安全的连接?

过去,我是在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.OKIsMutuallyAuthenticated是错误的。很明显,这是我要向客户端提供的证书的问题。

似乎客户端代码不能信任它所提供的证书,但是我已经在PC上本地安装了根CA。本地计算机和用户。如果我开了商店-并列出了证书,则在那里。

这似乎比应做的要困难。任何帮助都会有所帮助。

0 个答案:

没有答案