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