Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bouncycastle FIPs leaving a SecureRandom in heap #15889

Closed
galderz opened this issue Mar 19, 2021 · 5 comments · Fixed by #16105
Closed

Bouncycastle FIPs leaving a SecureRandom in heap #15889

galderz opened this issue Mar 19, 2021 · 5 comments · Fixed by #16105
Assignees
Labels
kind/bug Something isn't working
Milestone

Comments

@galderz
Copy link
Member

galderz commented Mar 19, 2021

Related 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 [email protected]/sun.security.ssl.DHKeyExchange$DHEPossession.generateDHKeyPair(DHKeyExchange.java:184)
	at [email protected]/sun.security.ssl.DHKeyExchange$DHEPossession.<init>(DHKeyExchange.java:163)
	at [email protected]/sun.security.ssl.DHClientKeyExchange$DHClientKeyExchangeProducer.produce(DHClientKeyExchange.java:185)
	at [email protected]/sun.security.ssl.ServerHelloDone$ServerHelloDoneConsumer.consume(ServerHelloDone.java:182)
	at [email protected]/sun.security.ssl.PostHandshakeContext.dispatch(PostHandshakeContext.java:81)
	at [email protected]/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1074)
	at [email protected]/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 [email protected]/java.net.Socket.getOutputStream(Socket.java:969)
	at org.jboss.logmanager.handlers.TcpOutputStream.flush(TcpOutputStream.java:214)
	at [email protected]/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.

@sberyozkin
Copy link
Member

@galderz thanks Galder, I'll start next week.

@Karm
Copy link
Member

Karm commented Mar 29, 2021

@jerboaa
Copy link
Contributor

jerboaa commented Mar 29, 2021

@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

@sberyozkin
Copy link
Member

@Karm @jerboaa thanks :-)

@sberyozkin
Copy link
Member

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants