没有 CA 的 SSL TrustStore,只有客户端证书
SSL TrustStore without CA, only client certificate
我有一个自定义的 CAroot.crt(由我生成),我所有的客户证书都是用这个 CAroot.crt 签名的。我有一个 TrustStore.jks,我只放置客户端证书而不是 CAroot.crt,因为我希望有可能随时从我的信任库中删除客户端。
当我尝试启动我的应用程序时,我得到以下信息:
*** Certificate chain
<Empty>
***
main, fatal error: 42: null cert chain
这是我的 trustStore.jks:
Keystore type: jks
Keystore provider: SUN
Your keystore contains 1 entry
Alias name: localhost
Creation date: Nov 23, 2019
Entry type: trustedCertEntry
Owner: CN=localhost, OU=IT, O=QUEROBUY, L=SAO CAETANO DO SUL, ST=SAO PAULO, C=BR
Issuer: CN=localhost, OU=IT, O=LANHELLAS XYZ, L=SAO CAETANO DO SUL, ST=SAO PAULO, C=BR
Serial number: 5416c04e360f9d50323c52d8a5b04be2969c9b86
Valid from: Sat Nov 23 16:39:54 BRT 2019 until: Tue Apr 06 16:39:54 BRT 2021
Certificate fingerprints:
MD5: 8F:29:1C:1F:05:89:0B:E6:A0:57:84:FE:B0:78:68:2D
SHA1: 95:C8:EA:0E:C8:7C:4E:99:E4:73:85:49:57:D6:BB:88:AF:52:52:12
SHA256: 7E:ED:19:AF:02:DB:CC:88:98:D0:10:4E:39:67:AA:4D:3F:70:DA:76:03:1B:CB:41:06:DC:3B:51:38:16:78:5F
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 1
*******************************************
*******************************************
如果我将 "CARoot.crt" 添加到我的 trustStore.jks 一切正常,但我失去了使某些特定客户端证书无效的机会。想象一下,我有 10 个客户端,每个客户端都有由 "CARoot.crt" 分配的您自己的证书 (.crt),但由于某种原因,客户端 001 应该立即失效,我将从 [=26] 中删除您的 public 密钥=] 在服务器中,没有它我应该等待证书到期日期。
TrustStore.jks 是 java 确定它是否信任证书的方式。它本质上是根证书的密钥库文件。如果您想避免 "not trustes messages."
,则必须将您的根证书添加到该存储区
在您的场景中,由于您使用该根颁发了 10 个客户端证书,因此从您的信任或密钥存储中删除 client_certificate.crt 不会不信任它。因为,根据设计,java 正在查看 TrustStore 并找到根证书,因此仍然信任 client_certificate.crt。您将需要重新设计您的 CA。
部署任何类型的 PKI 基础设施时,您还需要设置 CRL and/or OCSP 服务器。这是用于吊销证书的两个协议。
我还建议您不要直接从根目录发出 "end user certificates"。它最好从根目录颁发中间证书,然后使用 intermediate_certificate.crt 颁发您的实际服务器或客户端证书。
原因请看这里:https://security.stackexchange.com/questions/128779/why-is-it-more-secure-to-use-intermediate-ca-certificates#128800
这是使用 OpenSSL 部署您自己的 CA 的一种非常简单的方法。它将向您展示如何设置根服务器、中间服务器和吊销服务器。 https://jamielinux.com/docs/openssl-certificate-authority/
WHY: 如果您稍早查看调试日志,您会看到 CertificateRequest
消息,其中指定(除其他事项外)证书[ificate] 授权服务器要求;参见 rfc5246。 Java 将此定义为信任库中证书的主题名称,因为信任库中的证书通常被认为是 CA 证书(通常是 CA root 证书,因为预定义的是)。大多数客户端软件都遵循此指令,但也有例外。因此,如果您的信任库包含
这样的证书
Subject=Client1 Issuer=MyCA
Subject=Client2 Issuer=MyCA
Subject=Client3 Issuer=MyCA
那么您的服务器将要求 Client1 Client2 Client3
但 不是 MyCA
中的任何一个颁发的证书。如果客户端实际上只有一个证书并且它是 for 例如Client2
但 由 颁发 MyCA
-- 不是任何 Clientn
-- 大多数客户端软件会认为该证书对此 server/handshake.
PKI 方式。 证书不能在过期前失效是不正确的。通常,PKI 明确设计用于处理此类情况,通常称为 撤销 。证书在到期前被吊销的原因有多种;对于用于 SSL/TLS 的特定 PKI 方案(以及 Java 用于其他事情,如代码签名),即 PKIX(或有效等效的 X.509)参见 rfc5280 5.3.1 as well as the rest of section 5 for Certificate Revocation Lists (CRLs), the older and traditional way of handling revocation, and rfc6960 for Online证书状态协议 (OCSP),较新的方式。
对于 'real' (public) PKI 这主要是有效的。 Java 实现 PKIX 吊销检查,但对于 SSL/TLS (JSSE),它 默认禁用 ;您必须设置 sysprop com.sun.net.ssl.checkRevocation
才能使用它。您可能还需要为 CRL 设置 com.sun.security.enableCRLDP
,而 AFAICT 始终需要为 OCSP 设置 security 属性(不是 sysprop)ocsp.enable
。参见例如:
Check X509 certificate revocation status in Spring-Security before authenticating
Checking a X509 Certificate Revocation
但是 运行 CRL 分发点 and/or OCSP 响应器,以便它们是正确的 和 在需要时可用 -- 这可以任何时候——都是不平凡的;这是真正的 CA 收费(或获得补贴)的事情之一。为您自己的个人 CA 执行此操作可能会很麻烦,也可能实际上是不可能的,但如果您愿意,请对您的 CA 更加具体。
你的情况原则上比较简单;你只有一个 CA 并且你操作它,所以你知道何时发生撤销。当服务器更改时,您可以简单地向服务器提供 CRL。但是 AFAICS 内置代码无法 使用 该信息,因此您必须使用允许编写自己的 TrustManager 代替内置代码的挂钩,并修改它以使用带有使用 CRL 的 CertStore 的验证器。这可能也是相当多的工作,但只有一次。
变通方法。 不用 'right' PKI 术语,您可以继续通过修改服务器或客户端来单独信任叶证书的方法。
您可以更改服务器中的 (X509)TrustManager 挂钩以像往常一样验证证书,但将 getAcceptedIssuers
覆盖为 return [=76 的不同(并且适合您的情况)列表=] CA,导致 JSSE 发送 CertificateRequest,导致客户端使用他们正确的证书。
根据客户端的不同,您可以更改它们以忽略 'requested' CA 并发送它们的证书——服务器的默认 TrustManager 将验证它是否在信任库中( 或 CA 是)。对于 OpenSSL 这很容易; OpenSSL 已经忽略请求的 CA 列表,只发送配置的内容。对于 Java,您可以挂钩客户端 KeyManager 并覆盖 chooseClientAliases
方法,而不是像往常一样检查所需的发行者列表。对于其他客户,请添加到您的 Q 或询问新客户。
我有一个自定义的 CAroot.crt(由我生成),我所有的客户证书都是用这个 CAroot.crt 签名的。我有一个 TrustStore.jks,我只放置客户端证书而不是 CAroot.crt,因为我希望有可能随时从我的信任库中删除客户端。
当我尝试启动我的应用程序时,我得到以下信息:
*** Certificate chain
<Empty>
***
main, fatal error: 42: null cert chain
这是我的 trustStore.jks:
Keystore type: jks
Keystore provider: SUN
Your keystore contains 1 entry
Alias name: localhost
Creation date: Nov 23, 2019
Entry type: trustedCertEntry
Owner: CN=localhost, OU=IT, O=QUEROBUY, L=SAO CAETANO DO SUL, ST=SAO PAULO, C=BR
Issuer: CN=localhost, OU=IT, O=LANHELLAS XYZ, L=SAO CAETANO DO SUL, ST=SAO PAULO, C=BR
Serial number: 5416c04e360f9d50323c52d8a5b04be2969c9b86
Valid from: Sat Nov 23 16:39:54 BRT 2019 until: Tue Apr 06 16:39:54 BRT 2021
Certificate fingerprints:
MD5: 8F:29:1C:1F:05:89:0B:E6:A0:57:84:FE:B0:78:68:2D
SHA1: 95:C8:EA:0E:C8:7C:4E:99:E4:73:85:49:57:D6:BB:88:AF:52:52:12
SHA256: 7E:ED:19:AF:02:DB:CC:88:98:D0:10:4E:39:67:AA:4D:3F:70:DA:76:03:1B:CB:41:06:DC:3B:51:38:16:78:5F
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 1
*******************************************
*******************************************
如果我将 "CARoot.crt" 添加到我的 trustStore.jks 一切正常,但我失去了使某些特定客户端证书无效的机会。想象一下,我有 10 个客户端,每个客户端都有由 "CARoot.crt" 分配的您自己的证书 (.crt),但由于某种原因,客户端 001 应该立即失效,我将从 [=26] 中删除您的 public 密钥=] 在服务器中,没有它我应该等待证书到期日期。
TrustStore.jks 是 java 确定它是否信任证书的方式。它本质上是根证书的密钥库文件。如果您想避免 "not trustes messages."
,则必须将您的根证书添加到该存储区在您的场景中,由于您使用该根颁发了 10 个客户端证书,因此从您的信任或密钥存储中删除 client_certificate.crt 不会不信任它。因为,根据设计,java 正在查看 TrustStore 并找到根证书,因此仍然信任 client_certificate.crt。您将需要重新设计您的 CA。
部署任何类型的 PKI 基础设施时,您还需要设置 CRL and/or OCSP 服务器。这是用于吊销证书的两个协议。
我还建议您不要直接从根目录发出 "end user certificates"。它最好从根目录颁发中间证书,然后使用 intermediate_certificate.crt 颁发您的实际服务器或客户端证书。 原因请看这里:https://security.stackexchange.com/questions/128779/why-is-it-more-secure-to-use-intermediate-ca-certificates#128800
这是使用 OpenSSL 部署您自己的 CA 的一种非常简单的方法。它将向您展示如何设置根服务器、中间服务器和吊销服务器。 https://jamielinux.com/docs/openssl-certificate-authority/
WHY: 如果您稍早查看调试日志,您会看到 CertificateRequest
消息,其中指定(除其他事项外)证书[ificate] 授权服务器要求;参见 rfc5246。 Java 将此定义为信任库中证书的主题名称,因为信任库中的证书通常被认为是 CA 证书(通常是 CA root 证书,因为预定义的是)。大多数客户端软件都遵循此指令,但也有例外。因此,如果您的信任库包含
Subject=Client1 Issuer=MyCA
Subject=Client2 Issuer=MyCA
Subject=Client3 Issuer=MyCA
那么您的服务器将要求 Client1 Client2 Client3
但 不是 MyCA
中的任何一个颁发的证书。如果客户端实际上只有一个证书并且它是 for 例如Client2
但 由 颁发 MyCA
-- 不是任何 Clientn
-- 大多数客户端软件会认为该证书对此 server/handshake.
PKI 方式。 证书不能在过期前失效是不正确的。通常,PKI 明确设计用于处理此类情况,通常称为 撤销 。证书在到期前被吊销的原因有多种;对于用于 SSL/TLS 的特定 PKI 方案(以及 Java 用于其他事情,如代码签名),即 PKIX(或有效等效的 X.509)参见 rfc5280 5.3.1 as well as the rest of section 5 for Certificate Revocation Lists (CRLs), the older and traditional way of handling revocation, and rfc6960 for Online证书状态协议 (OCSP),较新的方式。
对于 'real' (public) PKI 这主要是有效的。 Java 实现 PKIX 吊销检查,但对于 SSL/TLS (JSSE),它 默认禁用 ;您必须设置 sysprop com.sun.net.ssl.checkRevocation
才能使用它。您可能还需要为 CRL 设置 com.sun.security.enableCRLDP
,而 AFAICT 始终需要为 OCSP 设置 security 属性(不是 sysprop)ocsp.enable
。参见例如:
Check X509 certificate revocation status in Spring-Security before authenticating
Checking a X509 Certificate Revocation
但是 运行 CRL 分发点 and/or OCSP 响应器,以便它们是正确的 和 在需要时可用 -- 这可以任何时候——都是不平凡的;这是真正的 CA 收费(或获得补贴)的事情之一。为您自己的个人 CA 执行此操作可能会很麻烦,也可能实际上是不可能的,但如果您愿意,请对您的 CA 更加具体。
你的情况原则上比较简单;你只有一个 CA 并且你操作它,所以你知道何时发生撤销。当服务器更改时,您可以简单地向服务器提供 CRL。但是 AFAICS 内置代码无法 使用 该信息,因此您必须使用允许编写自己的 TrustManager 代替内置代码的挂钩,并修改它以使用带有使用 CRL 的 CertStore 的验证器。这可能也是相当多的工作,但只有一次。
变通方法。 不用 'right' PKI 术语,您可以继续通过修改服务器或客户端来单独信任叶证书的方法。
您可以更改服务器中的 (X509)TrustManager 挂钩以像往常一样验证证书,但将 getAcceptedIssuers
覆盖为 return [=76 的不同(并且适合您的情况)列表=] CA,导致 JSSE 发送 CertificateRequest,导致客户端使用他们正确的证书。
根据客户端的不同,您可以更改它们以忽略 'requested' CA 并发送它们的证书——服务器的默认 TrustManager 将验证它是否在信任库中( 或 CA 是)。对于 OpenSSL 这很容易; OpenSSL 已经忽略请求的 CA 列表,只发送配置的内容。对于 Java,您可以挂钩客户端 KeyManager 并覆盖 chooseClientAliases
方法,而不是像往常一样检查所需的发行者列表。对于其他客户,请添加到您的 Q 或询问新客户。