如何通过 BouncyCastle JSSE 提供程序 + FIPS 提供程序有选择地使用仅批准模式?

How to selectively use approved-only mode with BouncyCastle JSSE provider + FIPS provider?

在 运行ning Java 8 上的一小段示例代码中,我尝试遵循 bc-fips-1.0.2.jar 用户指南中的建议, Legion of the Bouncy Castle Inc. BC-FJA 1.0.2 (Bouncy Castle FIPS Java API) User Guide Date: 09/14/19:

Note: support for FIPS mode appears to have started disappearing with Java 1.9, it has been confirmed that it is a null operation as of Java 11. For Java 11, or later, we recommend using the BCJSSE provider if you need FIPS support.

(第 11 页的脚注)。我在 'mixed' 上下文中执行此操作,因此大多数线程 运行 处于默认模式,一些 运行 处于 FIPS 仅批准模式。

但是,这似乎不起作用:似乎 'approved' 线程正在尝试重用 'unapproved' 线程创建的实例。

具体来说,当以编程方式启用 bc-fips-1.0.2.jar 的 BCFIPS 和 bctls-fips-1.0.10.jar 的 BCJSSE 时,在未修改的标准 OpenJDK 8(Corretto 8u232 in我的案例),并以编程方式删除内置的 SunJSSE 提供程序,然后在未批准模式的新线程上执行 HTTPS 连接,然后在批准模式的另一个新线程上执行 HTTPS 连接,导致异常:

Caused by: org.bouncycastle.crypto.fips.FipsUnapprovedOperationError: Attempt to use unapproved implementation in approved thread: SHA-512
    at org.bouncycastle.crypto.internal.io.Utils.approvedModeCheck(Unknown Source)
    at org.bouncycastle.crypto.internal.io.DigestOutputStream.write(Unknown Source)
    at org.bouncycastle.crypto.UpdateOutputStream.update(Unknown Source)
    at org.bouncycastle.jcajce.provider.BaseMessageDigest.engineUpdate(Unknown Source)
    at java.security.MessageDigest.update(MessageDigest.java:335)
    at org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider$NonceEntropySource$NonceEntropySourceSpi.runDigest(Unknown Source)
    at org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider$NonceEntropySource$NonceEntropySourceSpi.engineNextBytes(Unknown Source)
    at java.security.SecureRandom.nextBytes(SecureRandom.java:468)
    at org.bouncycastle.tls.crypto.impl.jcajce.JcaNonceGenerator.<init>(Unknown Source)
    at org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto.createNonceGenerator(Unknown Source)
    at org.bouncycastle.tls.AbstractTlsContext.createNonceGenerator(Unknown Source)
    at org.bouncycastle.tls.AbstractTlsContext.<init>(Unknown Source)
    at org.bouncycastle.tls.TlsClientContextImpl.<init>(Unknown Source)
[etc]

我尝试的完整重现方案位于 https://gist.github.com/marnix/834610d0fb92e53ce507edfce96bacb9,请参阅 class 的 javadoc 了解详细信息。

所以我的问题是:如何使用 BCJSSE 而不是 SunJSSE 使 HTTPS 连接工作,其中一些处于默认模式而另一些处于 FIPS 仅批准模式?

或者这在 Java 8 上不起作用,我是否必须等待 Java 9+ 才能开始工作? (为什么?)

(我的最终目标不是针对 HTTPS 连接,而是针对其他内容,其中大多数将 运行 处于默认模式,而一些线程将 运行 处于仅批准模式。)

使用单独的 SSLContext 实例是正确的方法,但在这里使用 SSLContext.setDefault 是非常错误的。部分原因是一旦删除线程连接,设置器就会出现竞争条件 b/w。但更重要的是,HttpsURLConnection 仅设置其默认 SSLSocketFactory 一次,并且最多会调用 SSLContext.getDefault 一次来设置它,因此之后调用 SSLContext.setDefault 将无效在 HttpsURLConnection 上,您将共享原始 SSLContext 和 FIPS 错误。

删除:

SSLContext.setDefault(context);

并替换:

url.openConnection()

与:

HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(context.getSocketFactory());