quarkus: QE Bouncy Castle FIPS JSSE native executable build fails after the BC FIPS version bump to 1.0.2.4

Describe the bug

I have app with org.bouncycastle:bc-fips and org.bouncycastle:bctls-fips dependencies that I build to native executable. After https://github.com/quarkusio/quarkus/pull/37354 build fails with exeception.

Expected behavior

Native executable is built.

Actual behavior

Native executable build fails:

GraalVM Native Image: Generating 'security-bouncycastle-fips-jsse-1.0.0-SNAPSHOT-runner' (executable)...
========================================================================================================================
For detailed information and explanations on the build output, visit:
https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/BuildOutput.md
------------------------------------------------------------------------------------------------------------------------
[1/8] Initializing...                                                                                    (5.0s @ 0.14GB)
 Java version: 21.0.1+12-LTS, vendor version: Mandrel-23.1.1.0-Final
 Graal compiler: optimization level: 2, target machine: x86-64-v3
 C compiler: gcc (redhat, x86_64, 8.5.0)
 Garbage collector: Serial GC (max heap size: 80% of RAM)
 5 user-specific feature(s):
 - com.oracle.svm.thirdparty.gson.GsonFeature
 - io.quarkus.runner.Feature: Auto-generated class by Quarkus from the existing extensions
 - io.quarkus.runtime.graal.DisableLoggingFeature: Disables INFO logging during the analysis phase
 - io.quarkus.security.BouncyCastleFeature
 - org.eclipse.angus.activation.nativeimage.AngusActivationFeature
------------------------------------------------------------------------------------------------------------------------
 6 experimental option(s) unlocked:
 - '-H:+AllowFoldMethods' (origin(s): command line)
 - '-H:BuildOutputJSONFile' (origin(s): command line)
 - '-H:-UseServiceLoaderFeature' (origin(s): command line)
 - '-H:AdditionalSecurityProviders' (origin(s): command line)
 - '-H:IncludeResources' (origin(s): command line)
 - '-H:ReflectionConfigurationResources' (origin(s): 'META-INF/native-image/io.netty/netty-transport/native-image.properties' in 'file:///project/lib/io.netty.netty-transport-4.1.100.Final.jar')
------------------------------------------------------------------------------------------------------------------------
Build resources:
 - 3.56GB of memory (11.4% of 31.10GB system memory, set via '-Xmx4g')
 - 12 thread(s) (100.0% of 12 available processor(s), determined at start)
19:22:14,397 INFO  [org.bou.jss.pro.PropertyUtils] Found boolean security property [keystore.type.compat]: true
19:22:15,309 INFO  [org.bou.jss.pro.PropertyUtils] Found string security property [jdk.tls.disabledAlgorithms]: SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, ECDH
19:22:15,310 INFO  [org.bou.jss.pro.PropertyUtils] Found string security property [jdk.certpath.disabledAlgorithms]: MD2, MD5, SHA1 jdkCA & usage TLSServer, RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224, SHA1 usage SignedJAR & denyAfter 2019-01-01
19:22:15,310 WARNING [org.bou.jss.pro.DisabledAlgorithmConstraints] Ignoring unsupported entry in 'jdk.certpath.disabledAlgorithms': SHA1 jdkCA & usage TLSServer
19:22:15,310 WARNING [org.bou.jss.pro.DisabledAlgorithmConstraints] Ignoring unsupported entry in 'jdk.certpath.disabledAlgorithms': SHA1 usage SignedJAR & denyAfter 2019-01-01
19:22:38,373 INFO  [org.bou.jss.pro.PropertyUtils] Found string system property [java.home]: /opt/mandrel
19:22:42,861 INFO  [org.bou.jss.pro.PropertyUtils] Found string system property [java.home]: /opt/mandrel
19:22:43,002 INFO  [org.bou.jss.pro.PropertyUtils] Found string system property [java.home]: /opt/mandrel
[2/8] Performing analysis...  [*****]                                                                   (36.6s @ 1.29GB)
   15,461 reachable types   (88.8% of   17,407 total)
   24,112 reachable fields  (61.9% of   38,931 total)
   77,354 reachable methods (59.9% of  129,172 total)
    4,580 types,   155 fields, and 3,669 methods registered for reflection
       61 types,    59 fields, and    55 methods registered for JNI access
        4 native libraries: dl, pthread, rt, z

Error: Unsupported features in 16 methods
Detailed message:
Error: 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. If these objects should not be stored in the image heap, you can use 

    '--trace-object-instantiation=org.bouncycastle.crypto.fips.FipsSecureRandom'

to find classes that instantiate these objects. Once you found such a class, you can mark it explicitly for run time initialization with 

    '--initialize-at-run-time=<culprit>'

to prevent the instantiation of the object.
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: Object was reached by
  reading field java.util.concurrent.atomic.AtomicReference.value of constant 
    java.util.concurrent.atomic.AtomicReference@46f3c81e: RandomSpi
  indexing into array java.util.concurrent.atomic.AtomicReference[]@1476359e: [Ljava.util.concurrent.atomic.AtomicReference;@1476359e
  reading field org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$PooledSecureRandomProvider.providerDefaultRandom of constant 
    org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$PooledSecureRandomProvider@ffc9672: org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$PooledSecureRandomProv...
  reading field org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider.providerDefaultSecureRandomProvider of constant 
    org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider@29120f33: BCFIPS version 1.000204
  reading field org.bouncycastle.jcajce.util.ProviderJcaJceHelper.provider of constant 
    org.bouncycastle.jcajce.util.ProviderJcaJceHelper@1782d427: org.bouncycastle.jcajce.util.ProviderJcaJceHelper@1782d427
  reading field org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider.helper of constant 
    org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider@27669d46: org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider@27669d46
  reading field org.bouncycastle.jsse.provider.BouncyCastleJsseProvider$1.val$cryptoProvider of constant 
    org.bouncycastle.jsse.provider.BouncyCastleJsseProvider$1@538fde3e: org.bouncycastle.jsse.provider.BouncyCastleJsseProvider$1@538fde3e
  reading field java.util.HashMap$Node.value of constant 
    java.util.HashMap$Node@5ef2c319: org.bouncycastle.jsse.provider.KeyManagerFactory=org.bouncycastle.jsse.provider....
  indexing into array java.util.HashMap$Node[]@cef2d6d: [Ljava.util.HashMap$Node;@cef2d6d
  reading field java.util.HashMap.table of constant 
    java.util.HashMap@55718cbb: {org.bouncycastle.jsse.provider.TrustManagerFactory=org.bouncycastle.jsse.provid...
  reading field org.bouncycastle.jsse.provider.BouncyCastleJsseProvider.creatorMap of constant 
    org.bouncycastle.jsse.provider.BouncyCastleJsseProvider@610628dc: BCJSSE version 1.0017
  reading field sun.security.jca.ProviderConfig.provider of constant 
    sun.security.jca.ProviderConfig@24446b40: BCJSSE
  indexing into array sun.security.jca.ProviderConfig[]@118b14af: [Lsun.security.jca.ProviderConfig;@118b14af
  reading field sun.security.jca.ProviderList.configs of constant 
    sun.security.jca.ProviderList@5e80e9e4: [BCJSSE]
  reading static field sun.security.jca.Providers.providerList
    at sun.security.jca.Providers.getSystemProviderList(Providers.java:195)
  parsing method sun.security.jca.Providers.getSystemProviderList(Providers.java:195) reachable via the parsing context
    at static root method.(Unknown Source)

Error: 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. If these objects should not be stored in the image heap, you can use 

    '--trace-object-instantiation=org.bouncycastle.crypto.fips.FipsSecureRandom'

to find classes that instantiate these objects. Once you found such a class, you can mark it explicitly for run time initialization with 

    '--initialize-at-run-time=<culprit>'

to prevent the instantiation of the object.
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: Object was reached by
  reading field java.util.concurrent.atomic.AtomicReference.value of constant 
    java.util.concurrent.atomic.AtomicReference@52b20d5a: RandomSpi
  indexing into array java.util.concurrent.atomic.AtomicReference[]@1476359e: [Ljava.util.concurrent.atomic.AtomicReference;@1476359e
  reading field org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$PooledSecureRandomProvider.providerDefaultRandom of constant 
    org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$PooledSecureRandomProvider@ffc9672: org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$PooledSecureRandomProv...
  reading field org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider.providerDefaultSecureRandomProvider of constant 
    org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider@29120f33: BCFIPS version 1.000204
  reading field org.bouncycastle.jcajce.util.ProviderJcaJceHelper.provider of constant 
    org.bouncycastle.jcajce.util.ProviderJcaJceHelper@1782d427: org.bouncycastle.jcajce.util.ProviderJcaJceHelper@1782d427
  reading field org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider.helper of constant 
    org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider@27669d46: org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider@27669d46
  reading field org.bouncycastle.jsse.provider.BouncyCastleJsseProvider$1.val$cryptoProvider of constant 
    org.bouncycastle.jsse.provider.BouncyCastleJsseProvider$1@538fde3e: org.bouncycastle.jsse.provider.BouncyCastleJsseProvider$1@538fde3e
  reading field java.util.HashMap$Node.value of constant 
    java.util.HashMap$Node@5ef2c319: org.bouncycastle.jsse.provider.KeyManagerFactory=org.bouncycastle.jsse.provider....
  indexing into array java.util.HashMap$Node[]@cef2d6d: [Ljava.util.HashMap$Node;@cef2d6d
  reading field java.util.HashMap.table of constant 
    java.util.HashMap@55718cbb: {org.bouncycastle.jsse.provider.TrustManagerFactory=org.bouncycastle.jsse.provid...
  reading field org.bouncycastle.jsse.provider.BouncyCastleJsseProvider.creatorMap of constant 
    org.bouncycastle.jsse.provider.BouncyCastleJsseProvider@610628dc: BCJSSE version 1.0017
  reading field sun.security.jca.ProviderConfig.provider of constant 
    sun.security.jca.ProviderConfig@24446b40: BCJSSE
  indexing into array sun.security.jca.ProviderConfig[]@118b14af: [Lsun.security.jca.ProviderConfig;@118b14af
  reading field sun.security.jca.ProviderList.configs of constant 
    sun.security.jca.ProviderList@5e80e9e4: [BCJSSE]
  reading static field sun.security.jca.Providers.providerList
    at sun.security.jca.Providers.getSystemProviderList(Providers.java:195)
  parsing method sun.security.jca.Providers.getSystemProviderList(Providers.java:195) reachable via the parsing context
    at static root method.(Unknown Source)

Error: 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. If these objects should not be stored in the image heap, you can use 

    '--trace-object-instantiation=org.bouncycastle.crypto.fips.FipsSecureRandom'

to find classes that instantiate these objects. Once you found such a class, you can mark it explicitly for run time initialization with 

    '--initialize-at-run-time=<culprit>'

to prevent the instantiation of the object.
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: Object was reached by
  reading field java.util.concurrent.atomic.AtomicReference.value of constant 
    java.util.concurrent.atomic.AtomicReference@84a1a52: RandomSpi
  indexing into array java.util.concurrent.atomic.AtomicReference[]@1476359e: [Ljava.util.concurrent.atomic.AtomicReference;@1476359e
  reading field org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$PooledSecureRandomProvider.providerDefaultRandom of constant 
    org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$PooledSecureRandomProvider@ffc9672: org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$PooledSecureRandomProv...
  reading field org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider.providerDefaultSecureRandomProvider of constant 
    org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider@29120f33: BCFIPS version 1.000204
  reading field org.bouncycastle.jcajce.util.ProviderJcaJceHelper.provider of constant 
    org.bouncycastle.jcajce.util.ProviderJcaJceHelper@1782d427: org.bouncycastle.jcajce.util.ProviderJcaJceHelper@1782d427
  reading field org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider.helper of constant 
    org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider@27669d46: org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider@27669d46
  reading field org.bouncycastle.jsse.provider.BouncyCastleJsseProvider$1.val$cryptoProvider of constant 
    org.bouncycastle.jsse.provider.BouncyCastleJsseProvider$1@538fde3e: org.bouncycastle.jsse.provider.BouncyCastleJsseProvider$1@538fde3e
  reading field java.util.HashMap$Node.value of constant 
    java.util.HashMap$Node@5ef2c319: org.bouncycastle.jsse.provider.KeyManagerFactory=org.bouncycastle.jsse.provider....
  indexing into array java.util.HashMap$Node[]@cef2d6d: [Ljava.util.HashMap$Node;@cef2d6d
  reading field java.util.HashMap.table of constant 
    java.util.HashMap@55718cbb: {org.bouncycastle.jsse.provider.TrustManagerFactory=org.bouncycastle.jsse.provid...
  reading field org.bouncycastle.jsse.provider.BouncyCastleJsseProvider.creatorMap of constant 
    org.bouncycastle.jsse.provider.BouncyCastleJsseProvider@610628dc: BCJSSE version 1.0017
  reading field sun.security.jca.ProviderConfig.provider of constant 
    sun.security.jca.ProviderConfig@24446b40: BCJSSE
  indexing into array sun.security.jca.ProviderConfig[]@118b14af: [Lsun.security.jca.ProviderConfig;@118b14af
  reading field sun.security.jca.ProviderList.configs of constant 
    sun.security.jca.ProviderList@5e80e9e4: [BCJSSE]
  reading static field sun.security.jca.Providers.providerList
    at sun.security.jca.Providers.getSystemProviderList(Providers.java:195)
  parsing method sun.security.jca.Providers.getSystemProviderList(Providers.java:195) reachable via the parsing context
    at static root method.(Unknown Source)

Error: 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. If these objects should not be stored in the image heap, you can use 

    '--trace-object-instantiation=org.bouncycastle.crypto.fips.FipsSecureRa

How to Reproduce?

Steps to reproduce:

  1. git clone git@github.com:quarkus-qe/quarkus-test-suite.git
  2. cd quarkus-test-suite/security/bouncycastle-fips/bcFipsJsse
  3. mvn clean verify -Dnative

Output of uname -a or ver

Fedora 38

Output of java -version

17

MANDREL 23.1.1.0 JDK 21.0.1+12-LTS

Quarkus version or git rev

999-SNAPSHOT

Build tool (ie. output of mvnw --version or gradlew --version)

Apache Maven 3.9.3

Additional information

No response

About this issue

  • Original URL
  • State: open
  • Created 7 months ago
  • Comments: 17 (16 by maintainers)

Most upvoted comments

May be Sun JSSE provider has to be removed instead and BC JSSE/FIPS then added at the end. I might’ve tried it too but can’t quite recall

@zakkak I’ve had a look today, with integration-tests/bouncycastle-fips-jsse (added a native test, https://github.com/quarkusio/quarkus/blob/2.10.0.Final/integration-tests/bouncycastle-fips-jsse/src/test/java/io/quarkus/it/bouncycastle/BouncyCastleFipsJsseITCase.java), there is a new final field in BouncyCastleFipsProvider:

  // Field descriptor #467 Lorg/bouncycastle/crypto/SecureRandomProvider;
  private final org.bouncycastle.crypto.SecureRandomProvider providerDefaultSecureRandomProvider;

where SecureRandomProvider is an interface, and BouncyCastleFipsProvider$PooledSecuredRandomProvider seems to implement it which leads to

// Field descriptor #54 [Ljava/util/concurrent/atomic/AtomicReference;
  // Signature: [Ljava/util/concurrent/atomic/AtomicReference<Ljava/security/SecureRandom;>;
  private final java.util.concurrent.atomic.AtomicReference[] providerDefaultRandom;

and then during the native build:

Trace: Object was reached by
  reading field java.util.concurrent.atomic.AtomicReference.value of constant 
    java.util.concurrent.atomic.AtomicReference@374b8d8c: RandomSpi
  indexing into array java.util.concurrent.atomic.AtomicReference[]@3c425ce4: [Ljava.util.concurrent.atomic.AtomicReference;@3c425ce4
  reading field org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$PooledSecureRandomProvider.providerDefaultRandom of constant 
    org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$PooledSecureRandomProvider@7722f86d: org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$PooledSecureRandomProv...
  reading field org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider.providerDefaultSecureRandomProvider of constant 
    org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider@58156512: BCFIPS version 1.000204
  reading field org.bouncycastle.jcajce.util.ProviderJcaJceHelper.provider of constant 

I’ve tried 3 things:

  • Runtime reinitialize org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$PooledSecuredRandomProvider
  • Reset that field:
@com.oracle.svm.core.annotate.TargetClass(className = "org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$PooledSecuredRandomProvider", onlyWith = BouncyCastleFips.class)
final class Target_org_bouncycastle_jcajce_provider_BouncyCastleFipsProvider$PooledSecuredRandomProvider {
    @Alias
    @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) //
    private java.util.concurrent.atomic.AtomicReference<java.security.SecureRandom>[] providerDefaultRandom;
}

in both cases having a similar message, here is the one when the substitution is used:

com.oracle.svm.core.util.UserError$UserException: Substitution target for io.quarkus.security.runtime.graal.Target_org_bouncycastle_jcajce_provider_BouncyCastleFipsProvider$PooledSecuredRandomProvider is not loaded. Use field `onlyWith` in the `TargetClass` annotation to make substitution only active when needed.

Please have a quick look next week if you can, keeping fingers crossed it will be an easy one for you 😃

Thanks

@michalvavrik https://quarkus.io/guides/security-customization#bouncy-castle-jsse-fips documents this is currently not supported in native, so a bit of a good news it does not break any user expectations, but I’ll give it another try, as soon as possible, will try again @zakkak 's suggestions at #14139 etc

makes sense, I’ve since found out we only have @QuarkusTest for this, which is bit unusual and we only build native executable but don’t test it. I suppose it is related. Thanks

@michalvavrik Sure but in both cases it is not BC FIPS on its own but the BC_FIPS and BC_TLS_FIPS combo which is specifically about securing the TLS connection as opposed to just dealing with the FIPS algorithms.

Let me adjust the title a bit

@michalvavrik native build passes in Quarkus, may be more substitutions are needed, I’m not seeing there where exactly that SecureRandom is set.

By the way it is not supported at the product level