我同意 EJP 的答案,但由于您接受了不同的答案,因此以下是有关自签名证书问题的更多详细信息。
可以在您的服务器上使用自签名证书。您只需配置所有潜在客户端即可使用信任此证书。这可以通过将证书(没有私钥)导入到每台计算机的受信任存储中或浏览器的受信任证书存储库中(例如,Firefox 使用自己的证书,独立于其运行的操作系统)来完成。这里的自签名服务器证书主要是自定义 CA 证书的特例,其中每个客户端都需要了解它可能使用的每个服务器(缺点是自签名证书无法撤销)。这没问题,但实际上,如果您拥有的机器不多,这很快就会成为问题。
您的主要问题将与自签名证书有关client证书。
客户端证书身份验证由服务器发起,服务器向客户端发送 TLS 证书请求消息。该消息包含它愿意接受的证书颁发机构的名称列表。然后,客户端使用此列表来选择要发送的证书:它们查找具有与此 CA 列表中的名称之一匹配的颁发者 DN 的证书(它们拥有私钥)(它们也可以使用证书链,如果中间 CA需要证书才能链接到此 CA 列表中的颁发者 DN)。
如果大多数客户端找不到符合这些条件的证书,则根本不会发送任何客户端证书。当尝试使用自签名客户端证书时,这将是最大的问题。
解决此问题的一种方法是让服务器发送一个空列表。这为客户端提供了更多选择证书的自由(然后由服务器选择是否接受它,但无论如何情况总是如此)。这是 TLS 1.1 明确允许的,之前的版本 (SSLv3/TLS 1.0) 在这个主题上保持沉默,但在实践中,据我所知,它也适用于大多数 SSLv3/TLS 1.0 堆栈。 (例如,当浏览器自动选择证书时,这仍然可能导致交互笨拙,因为它很难正确地进行自动选择。)
Java's X509TrustManager
可以使用定制getAcceptedIssuers()
在 TLS 证书请求消息中返回空 CA 列表。据我所知,在 C#/.Net 中,SslStream
's RemoteCertificateValidationCallback
没有它的等价物。据我所知,此列表是使用 IIS/ 时机器的受信任证书列表构建的SslStream
。 (请注意,这与证书验证本身无关,它只是关于服务器通告它可能接受哪些证书。)
此外,如果您想使用带有自签名证书的客户端证书身份验证,则必须在服务器中实现您自己的验证回调来执行此身份验证。一个简单的示例是从您获得的证书中提取公钥,将其与服务器具有的预定义列表进行比较,然后使用该预定义列表中的用户名。你不能相信自签名证书所说的任何内容,除非你有一种明确的方法来根据你所知道的内容检查其内容。实现一个回调,只说return true;
不会执行任何身份验证。任何人都可以构建具有相同名称或属性和不同密钥的证书。 (最好在服务器可信证书存储中明确信任每个客户端证书,尽管这可能会导致 TLS 证书请求消息中出现很长的 CA 列表。)
如果您不想依赖商业 CA,请构建您自己的 CA。这可能需要一些工作(主要是管理工作),但至少您将拥有一个更干净的结果系统。通过使用该 CA 证书配置客户端和服务器,您应该能够扩展到更多客户端和服务器,而无需进行任何更改,并且在请求客户端证书时,您还可以从正常的 CA 列表行为中受益。