Bouncycastle FIPs leaving a SecureRandom in heap
See original GitHub issueRelated to #14904. One of the failures is related to quarkus-integration-test-bouncycastle-fips
module:
Error: Unsupported features in 8 methods
Detailed message:
Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Detected an instance of Random/SplittableRandom class in the image heap. Instances created during image generation have cached seed values and don't behave as expected. To see how this object got instantiated use --trace-object-instantiation=java.security.SecureRandom. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
Trace:
at parsing org.bouncycastle.crypto.general.DSA$1.hasTestPassed(Unknown Source)
Call path from entry point to org.bouncycastle.crypto.general.DSA$1.hasTestPassed(AsymmetricCipherKeyPair):
at org.bouncycastle.crypto.general.DSA$1.hasTestPassed(Unknown Source)
at org.bouncycastle.crypto.general.DSA$1.hasTestPassed(Unknown Source)
at org.bouncycastle.crypto.general.SelfTestExecutor.validate(Unknown Source)
at org.bouncycastle.crypto.general.GOST3410.validateKeyPair(Unknown Source)
at org.bouncycastle.crypto.general.GOST3410.access$100(Unknown Source)
at org.bouncycastle.crypto.general.GOST3410$KeyPairGenerator.doGenerateKeyPair(Unknown Source)
at org.bouncycastle.crypto.general.GuardedAsymmetricKeyPairGenerator.generateKeyPair(Unknown Source)
at org.bouncycastle.jcajce.provider.ProvRSA$KeyPairGenerator.generateKeyPair(Unknown Source)
at java.base@11.0.12-internal/sun.security.ssl.DHKeyExchange$DHEPossession.generateDHKeyPair(DHKeyExchange.java:184)
at java.base@11.0.12-internal/sun.security.ssl.DHKeyExchange$DHEPossession.<init>(DHKeyExchange.java:163)
at java.base@11.0.12-internal/sun.security.ssl.DHClientKeyExchange$DHClientKeyExchangeProducer.produce(DHClientKeyExchange.java:185)
at java.base@11.0.12-internal/sun.security.ssl.ServerHelloDone$ServerHelloDoneConsumer.consume(ServerHelloDone.java:182)
at java.base@11.0.12-internal/sun.security.ssl.PostHandshakeContext.dispatch(PostHandshakeContext.java:81)
at java.base@11.0.12-internal/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1074)
at java.base@11.0.12-internal/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1061)
at app//com.oracle.svm.core.jdk.Target_java_security_AccessController.doPrivileged(SecuritySubstitutions.java:118)
at java.base@11.0.12-internal/java.net.Socket.getOutputStream(Socket.java:969)
at org.jboss.logmanager.handlers.TcpOutputStream.flush(TcpOutputStream.java:214)
at java.base@11.0.12-internal/java.io.PrintStream.flush(PrintStream.java:417)
at app//com.oracle.svm.jni.functions.JNIFunctions.ExceptionDescribe(JNIFunctions.java:782)
The issue arises from org.bouncycastle.crypto.general.Utils
which contains static final SecureRandom testRandom = new SecureRandom();
. This class is initialized at build time through:
Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Detected an instance of Random/SplittableRandom class in the image heap. Instances created during image generation have cached seed values and don't behave as expected. Object has been initialized by the org.bouncycastle.crypto.general.AES class initializer with a trace:
at java.security.SecureRandom.<init>(SecureRandom.java:218)
at org.bouncycastle.crypto.general.Utils.<clinit>(Unknown Source)
at org.bouncycastle.crypto.general.AES$AuthParameters.<init>(Unknown Source)
at org.bouncycastle.crypto.general.AES.<clinit>(Unknown Source)
The issue can be solved with a substitution like this. It bypasses the internal check to validation step of generated key/value pairs:
@TargetClass(className = "org.bouncycastle.crypto.general.DSA$1")
final class Target_org_bouncycastle_crypto_general_DSA$1 {
@Substitute
public boolean hasTestPassed(Target_org_bouncycastle_crypto_internal_AsymmetricCipherKeyPair kp) {
return false;
}
}
@TargetClass(className = "org.bouncycastle.crypto.internal.AsymmetricCipherKeyPair")
final class Target_org_bouncycastle_crypto_internal_AsymmetricCipherKeyPair {
}
Another option would be for org.bouncycastle.crypto.general.AES
and other related classes be runtime initialized. Quarkus experts should provide some input on this possibility.
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (5 by maintainers)
Top Results From Across the Web
Bouncy Castle Getting FipsSecureRandom - Stack Overflow
I'm trying to use Bouncy Castle in approved mode ( CryptoServicesRegistrar. ... Fips.Utils.ValidateRandom(SecureRandom random, Int32 ...
Read more >The Bouncy Castle FIPS Java API in 100 Examples
If no SecureRandom has been specified using CryptoServicesRegistrar.setSecureRandom() the provider class will generate a FIPS compliant DRBG based on SHA-512.
Read more >LibJitsi BouncyCastle FIPS port - developers & users
It appears BouncyCastle's FIPS library uses SecureRandom everywhere internally, and the default SecureRandom that the BCFIPS provider ...
Read more >Key Generation on FIPS device or using SW with FIPS generator
AES key is generated using BouncyCastle library and SecureRandom source is provided from FIPS 140-2 Level 3 device with validated RNG. Are these ......
Read more >Java Cryptography Architecture (JCA) Reference Guide
The Security Class; The SecureRandom Class; The MessageDigest Class ... The providers are ordered by preference from left to right (1-3).
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
@sberyozkin It should be reproducible with Graal VM 21.1.0-dev snapshots from here too: https://github.com/graalvm/graalvm-ce-dev-builds/releases/tag/21.1.0-dev-20210325_0249
@RuntimeReInitialized
does not really work as BouncyCastle provider is set by the recorder at the static initialization time. But substitutions work - I think this is fine for now - the self-tests for some cases are skipped in the native mode - and it can be documented.