【问题标题】:Self-signed Certificate and Client Keystore for SSL Authentication用于 SSL 身份验证的自签名证书和客户端密钥库
【发布时间】:2015-09-03 12:22:17
【问题描述】:

我需要在服务器(一个 XML 硬件设备)上创建并安装一个自签名证书,以对 Java 客户端/应用程序进行 SSL 身份验证,通过其接口配置,可以设置 keystores,即.jks。出于显而易见的原因,我只需要此设置用于测试目的而不是生产。以下是我创建 keystorePKCS12 类型)的方式:

1) 生成私钥(对)

$> openssl genrsa -des3 -out private.key 1024

2) 生成证书请求(需要这样做吗?)——我只将值设置为 CN

$> openssl req -new -key private.key -out request.csr

3) 创建自签名证书

$> openssl x509 -req -days 365 -in request.csr -signkey private.key -out cert.crt

4) 创建PKCS12 密钥库

$> openssl pkcs12 -export -in cert.crt -inkey private.key -out keystore.p12

5) 创建客户端JKS

$> keytool -importkeystore -srckeystore keystore.p12 -srcstoretype pkcs12 -srcalias myalias -destkeystore client.jks -deststoretype jks -deststorepass <same pass as private key> -destalias myalias

当我在服务器/设备上安装 keystore.p12,在客户端 Java 应用程序上安装 client.jks 并发出请求时,我收到以下错误:

javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate

我是否从根本上遗漏了有关证书和 SSL 身份验证的内容?

【问题讨论】:

  • 您可以使用 keytool 完成所有操作。这里根本不需要 OpenSSL。
  • 您似乎对服务器(keystore.p12)和您的 Java 客户端(client.jks,显然也用作信任库)使用相同的密钥+自己的证书;这通常是一个坏主意,但可以接受测试。您不识别服务器。但是使用 p12 配置其密钥+自己的证书(密钥库)的服务器软件可以单独配置其受信任的证书(信任库)。这可能是一个不同的文件,可能采用不同的格式,或者它可能是隐含的,如 Windows“证书”存储或 MacOSX 钥匙串。寻找一种将您的证书(不是密钥或 p12,只是证书)添加到服务器信任库的方法。
  • @dave_thompson_085 keystoretruststore 分离,你是说我需要创建一个 client keystore(私有key + 自签名证书),即client.jks,提取其证书,并最终将其添加到servertruststore?可以用serverp12顺便给它加上client的认证——更像是用server i> 的 p12 既是 truststore 又是 keystore?并且 serverkeystore 是否应该拥有自己的私钥+证书,或者我只能添加 client 的证书到服务器的空TS/KS?
  • This post 包含一个脚本,该脚本使用 keytool 创建证书颁发机构、服务器和客户端证书以及信任库。

标签: java ssl certificate keystore keytool


【解决方案1】:

还没有答案,但是对于 cmets 来说太复杂了,所以我会先开始并稍后编辑。

(SSL/TLS)服务器和客户端是否应该共享一个密钥(和证书)? 可以用于开发和测试,但因生产而异。作为一般规则,每个需要进行身份验证的独立系统都应该有自己的私钥和该密钥的证书(或者有时但很少有多个证书)。如果所涉及的两个(或更一般地说是所有)系统以及它们之间的通信都将受到同一管理员的控制,那么放宽此规则并(重新)使用一个密钥+证书并没有什么坏处。由于所使用的密钥+证书应该始终是(重新)可配置的,因此您可以稍后更改,甚至在需要或必要时更改多次。

证书应该是自签名的吗? 通常适用于开发和测试,但因生产而异。同样,如果所有相关系统都在一个管理员的控制之下,或者至少是有限的一组相互认识的人(例如一个组织的部门或办公室),那么 CA 就没有真正的安全需求来验证身份和确定信任。一个考虑因素是服务器证书必须对证书中的域名(或 IP 地址,如果您使用该选项)进行编码,因此在开发和测试中经常需要更改它们,这意味着返回新证书的 CA,至少是轻微的麻烦,有时是延迟。

目前,您有一个密钥和自签名证书,您正在尝试为客户端和服务器共享。虽然您可能希望稍后更改这些内容,但我建议您首先关注让 something 工作。同时改变几个相互关联的东西往往会引起混乱。

“提取”证书? 对于当前设置,使用一个(共享)密钥+证书(自签名),您已经在 J​​KS 中拥有密钥+证书,相同的密钥+证书在一个 P12,以及文件 (cert.crt) 中的相同证书,因此您无需提取任何内容。如果您(稍后)使用 keytool 为 Java(客户端)端生成新密钥和自签名证书,是的,您需要提取该证书。 如果您获得现有密钥或新密钥的 CA 签名证书,您可能需要提取根/锚点,但您可能已经拥有它,见下文。

需要信任哪些证书?客户端始终(除了与此处无关的小例外)在其信任库中需要服务器证书的,并且当客户端身份验证(也称为双向或双向)用于您的情况时,服务器在其信任库中需要客户端证书的 anchor。在您当前的情况下,客户端和服务器使用相同的证书,因此双方都需要相同的锚点。

  • 对于自签名证书,锚点必须是证书本身——必须更改,通常是手动更改,任何时候合作伙伴证书更改。

  • 对于 CA 颁发的 证书,锚可以是并且(总是?)应该是该 CA 的 root 证书; CA 根通常是长期存在的(例如 20 年或更长时间),并且在合作伙伴/实体证书发生时不需要更改。

  • 如果您使用像 Verisign 或 GoDaddy 这样的知名 CA,而不是您自己运行的 CA,或者可能由您当地红色的“Joe's Dicount Liquor Store and Certificate Authority”运行-light District,在某些系统中,那些知名 CA 的根可能已经安装,在这种情况下您无需执行任何操作。

客户端如何信任服务器?您的 Java 客户端显然将 client.jks 文件用作密钥库和信任库。这很容易实现,因为 Java 使用一种可以包含两种数据的文件格式,并且进一步将自有密钥条目中的证书视为也是受信任的证书(锚点)。

服务器信任库呢?另一方面,使用 pkcs12 格式作为密钥库的软件,或者至少用于导入密钥库条目的软件,有时(我' d 经常说)不会为其信任库使用相同的格式,当然也不会使用相同的文件。它确实拒绝客户端使用它已经拥有的与其自己的证书相同的证书这一事实可能意味着它不会将您提供给它的 pkcs12 视为信任库数据,尽管在原则上它可能不喜欢其他东西,例如缺少 ExtendedKeyUsage 扩展或撤销/状态数据不可用。

您没有识别或描述作为您的服务器的设备,因此我只能猜测 SSL/TLS 服务器(尤其是嵌入式服务器)可以工作的无数方式。但是某处在您的设备中有可能一种将证书添加到其信任库的方法。此外,它应该在某处有某种错误日志,其中可能包含有关它是否只需要信任库中的锚(这里是自签名证书)或其他东西的附加信息——假设你可以看到该日志无需 SSL/TLS 身份验证!

如果您可以在您的服务器/设备上向我们提供(链接)文档,或者足够详细地告诉我们它显示、提供和/或接受的内容,我可能会更具体。

【讨论】:

  • 您的回答非常全面且内容丰富。鉴于我在客户端(JKS 格式)和服务器(具有 PKCS#12 格式的 XML 设备——因为它不支持 JKS)上安装了相同的密钥库,从逻辑上讲,服务器应该认为客户端的证书是值得信赖的并对其进行身份验证。可以这么说,由于设备的配置没有快速刷新,问题就出现了。几个小时后重试连接,我能够在客户端工具中看到成功的 SSL 握手(抱歉,我无法透露两者的身份)。
  • @Ulvon "Logically" 使用 PKCS#12 安装自己的证书和密钥在其他人使用时不需要信任相同的证书;我可以向您展示它不这样做的程序。您正在使用的特定设备显然确实(延迟后);所以你很幸运。
  • @dave-thompson-085 我不明白你的第一句话。您是说为该证书安装了 PKCS#12 密钥库的服务器会验证另一个客户端,即使它带有另一个证书?
猜你喜欢
  • 2011-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-15
  • 1970-01-01
  • 1970-01-01
  • 2018-10-20
  • 2023-03-19
相关资源
最近更新 更多