ssl - BouncyCastle JSSE 和 BCTLS 没有密码凭证
问题描述
为我的服务器应用程序使用 BouncyCastle FIPS JSSE 和 TLS 提供程序。
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-fips</artifactId>
<version>1.0.3</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bc-fips</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bctls-fips</artifactId>
<version>1.0.10</version>
</dependency>
在应用程序中配置 FIPS 和 JSSE 提供程序,如下所示。
Security.insertProviderAt(new BouncyCastleFipsProvider(), 1);
Security.insertProviderAt(new BouncyCastleJsseProvider("fips:BCFIPS"), 2);
Security.setProperty("keystore.type", "BCFKS");
SSL证书配置如下:
Server Cert - Public Key: RSA 2048 bit, Sign Algorithm: SHA256WithRSA
Issuing CA - Public Key: RSA 2048 bit, Sign Algorithm: SHA256WithRSA
Root CA - Public Key: RSA 2048 bit, Sign Algorithm: SHA1WithRSA
使用 Zulu OpenJDK JRE 11。以下是与 TLS 相关的其他系统属性
-Djdk.tls.disabledAlgorithms="MD5, RC4, TLSv1, SSLv2Hello, SSLv3, DSA, DESede, DES, 3DES, DES40_CBC, RC4_40, MD5withRSA, DH, 3DES_EDE_CBC, DHE, DH keySize < 1024, EC keySize < 224" -Djdk.tls.ephemeralDHKeySize=2048 -Djdk.tls.rejectClientInitiatedRenegotiation=true -Djava.security.egd=file:/dev/./urandom -Dorg.bouncycastle.rsa.allow_multi_use=true
支持的协议是 TLSv1.2。
期待:
我希望服务器支持 TLS_ECDHE_RSA 类型的密码。当使用具有相同配置(减去上面的 BC 库)的 Sun JSSE 的相同应用程序时,启用这些密码。
实际的:
问题是在 SSL 扫描中仅显示 TLS_RSA 类型的密码,如下所示:
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
在 bouncycastle 调试日志中,我看到以下条目
[o.b.j.p.ProvTlsServer] - Server found no credentials for cipher suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
[o.b.j.p.ProvTlsServer] - Server found no credentials for cipher suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
[o.b.j.p.ProvTlsServer] - Server found no credentials for cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
[o.b.j.p.ProvTlsServer] - Server found no credentials for cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
[o.b.j.p.ProvTlsServer] - Server found no credentials for cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
[o.b.j.p.ProvTlsServer] - Server found no credentials for cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
这意味着什么?我没有从谷歌搜索中找到任何有用的信息。有人可以帮助如何解决这个问题。
提前致谢。
可能的类似问题:BouncyCastle 提供者未公开 DHE 密码
更新 1
这是按照以下答案中的建议将ssl.KeyManagerFactory.algorithm
and设置为 PKIX 后的更新。ssl.TrustManagerFactory.algorithm
感谢您建议该配置。现在 TLS_ECDHE_RSA* 密码出现在 SSL 扫描中。
然而,有一个担忧。受支持的密码列表还包括TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
(参考屏幕截图),根据本文档(附录-B)在 FIPS 模式下不受支持:https://downloads.bouncycastle.org/fips-java/BC-FJA-(D) TLSUserGuide-1.0.10.pdf。
我已经设置了系统属性-Dorg.bouncycastle.fips.approved_only=true
,但没有发现任何区别。
我不确定这是否是预期的。对此有什么想法吗?
其他观察:
一旦我按照上面的建议配置了 PKIX 算法,我很快就开始org.bouncycastle.crypto.IllegalKeyException: Attempt to sign/verify with RSA modulus already used for encrypt/decrypt.
在 SSL 扫描后收到错误。此错误阻止了与我的应用程序的所有后续 TLS 连接。为此,我尝试了以下两种方法。
设置
-Dorg.bouncycastle.jsse.fips.allowRSAKeyExchange=false
如本论坛所述。但是,这禁用了所有 TLS_RSA 密码。配置了系统属性
-Dorg.bouncycastle.rsa.allow_multi_use=true
。有了这个,我可以同时使用 TLS_RSA 和 TLS_ECDHE_RSA 密码。
解决方案
这些日志条目(“服务器找不到凭据...”意味着服务器配置为支持上述算法,但无法通过初始化 SSLContext 的 X509KeyManager 找到合适的凭据(密钥加证书)。
BCJSSE(尤其是 FIPS)不与其他提供商的 KeyManagerFactory 或 TrustManagerFactory 互操作,因此请检查您是否已将默认算法配置为 PKIX(在 java.security 中)以使用 BCJSSE 算法:
ssl.KeyManagerFactory.algorithm=PKIX
ssl.TrustManagerFactory.algorithm=PKIX
否则:KeyManagerFactory 没有正确初始化(KeyStore 有问题),或者 chooseServer... 方法调用未能找到任何适合 RSA 签名的凭证,或者它们已经过期,或者 KeyUsage 或 ExtendedKeyUsage 不兼容,或者其他一些细节。在某些情况下,我们确实有比 SunJSSE 更严格的条件。如果您可以将日志记录级别降低到 FINEST,您应该会看到更多与失败查找相关的条目(为此可能需要升级到 bctls-fips 的 1.0.11)。
我们为 bctls-fips 提供了一个源 jar,因此如果您能够在调试器中查看 X509KeyManager 调用,您可以追踪未找到可接受凭据的具体原因。否则,我们将需要查看证书的更多详细信息。在这种情况下,在我们的 GitHub 上提出问题可能会更好。
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:我相信这是允许的,所以这是文档中的错误。
如果您处于批准模式,则不能将单个 RSA 密钥用于签名/验证和加密/解密。TLS_RSA_* 密码套件将使用密钥在服务器进行解密,而 TLS_ECDHE_RSA_* 密码套件将使用密钥进行签名。为了启用这两者,您需要为每种情况使用单独的 RSA 凭据,一个使用 KeyUsage 'digitalSignature',一个使用 KeyUsage 'keyEncipherment'(因此 KeyManager 知道在每种情况下使用哪个)。org.bouncycastle.rsa.allow_multi_use 可以让它用于调试目的,但它不符合 FIPS 允许在批准模式下多次使用。org.bouncycastle.jsse.fips.allowRSAKeyExchange 可用于禁用 TLS_RSA_*,建议这样做,因为无论如何这些都是过时的密码套件。
推荐阅读
- wolfram-mathematica - 如何将当前迭代的答案与 Mathematica 中的前一个进行比较
- node.js - VueJS 自定义组件导入有时有效
- c# - 使用 Graph SDK - C# 获取文件夹内容
- arrays - 快速根据案例名称过滤枚举
- android - 应用更新被拒绝,说明我的应用 Sush com.toto.sush 不符合使用 READ_SMS、SEND_SMS、READ_CALL_LOG 的条件
- google-calendar-api - Google 日历推送通知:创建之前/之后的新事件和事件验证
- mysql - 如何将多行相乘?(业余)
- php - 在 PHP 中使用 webhook 将文件上传到 Discord
- python - timeit() 的更具体定义是什么,或者它有什么作用?
- javascript - 发布请求后出现“发送到客户端后无法设置标头”错误