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

Add BouncyCastle providers to generated AutoFeature #23527

Merged
merged 1 commit into from
Mar 8, 2022

Conversation

sberyozkin
Copy link
Member

@sberyozkin sberyozkin commented Feb 8, 2022

Fixes #17046
Related to #23967

Hi @zakkak

The following trace is produced when BouncyCastleEndpoint.checkAesCbcPKCS7PaddingCipher is run in native:

Caused by: com.oracle.svm.core.jdk.UnsupportedFeatureError: Trying to verify a provider that was not registered at build time: BC version 1.7. All providers must be registered and verified in the Native Image builder. 
	at com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:89)
	at javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:403)
	at javax.crypto.Cipher.getInstance(Cipher.java:690)
	at javax.crypto.Cipher.getInstance(Cipher.java:625)
	at io.quarkus.it.bouncycastle.BouncyCastleEndpoint.checkAesCbcPKCS7PaddingCipher(BouncyCastleEndpoint.java:68)

But we do register it at build time as the additional security provider. It is verified OK in all other native tests in the integration test. Is it possible to verify somehow the BC provider is registered in Native, I recall you did some manual updates to GraalVM to trace it.

I wonder if something might've changed in the latest GraalVM, as the user confirms it worked in Quarkus 1.x

@zakkak
Copy link
Contributor

zakkak commented Feb 10, 2022

Hi @sberyozkin,

It looks like GraalVM is not able to detect the BC provider despite being registered at build time in a static initializer.
The reason is that GraalVM determines which Providers are being used during the "analysis" phase which precedes the static initialization.

So to resolve this we will need to move the Security.addProvider(new BouncyCastleProvider()); invocation out of the static initializer and place it in the generated io.quarkus.runner.AutoFeature.

What's interesting is why it works for the other tests, since we follow the same approach there... My suspicion is that due to

nativeImageArgs.add("-H:AdditionalSecurityProviders=" + additionalSecurityProviders);

we trick the tests into thinking the provider is available, but the actual implementation ends up coming from a different provider, I haven't verified that part yet though.

@sberyozkin
Copy link
Member Author

sberyozkin commented Feb 10, 2022

Hi @zakkak Thanks for this analysis,

So to resolve this we will need to move the Security.addProvider(new BouncyCastleProvider()); invocation out of the static initializer and place it in the generated io.quarkus.runner.AutoFeature.

But I wonder how it can be done without tying that code to Security.addProvider(new BouncyCastleProvider()); since this provider is registered only if it was requested with the quarkus.security.security-providers=BC property ?

What's interesting is why it works for the other tests, since we follow the same approach there

Let me debug that a bit later today - I thought I noticed a different code branch was used in JVM mode.
All other tests there use BC when requesting a key pair or signature, etc, and some of them further check it is BC-produced, so I'd say it is something specific to getting Cipher

@zakkak
Copy link
Contributor

zakkak commented Feb 10, 2022

But I wonder how it can be done without tying that code to Security.addProvider(new BouncyCastleProvider()); since this provider is registered only if it was requested with the quarkus.security.security-providers=BC property ?

The AutoFeature is generated every time we perform a native compilation, so (in theory at least) we can still invoke Security.addProvider(); with the correct providers according to quarkus.security.security-providers. Please feel free to reach out to me for a call or chat if you think it would help get things more clear.

@zakkak
Copy link
Contributor

zakkak commented Feb 10, 2022

As a proof of concept I tested your branch with:

diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java
index 9e7a72807f..03275e4f0a 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java
@@ -1,5 +1,6 @@
 package io.quarkus.deployment.steps;
 
+import static io.quarkus.gizmo.MethodDescriptor.ofConstructor;
 import static io.quarkus.gizmo.MethodDescriptor.ofMethod;
 
 import java.io.ObjectStreamClass;
@@ -10,6 +11,8 @@ import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.nio.charset.StandardCharsets;
+import java.security.Provider;
+import java.security.Security;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -207,6 +210,9 @@ public class NativeImageAutoFeatureStep {
             }
         }
 
+        ResultHandle bcProvider = overallCatch.newInstance(ofConstructor("org.bouncycastle.jce.provider.BouncyCastleProvider"));
+        overallCatch.invokeStaticMethod(ofMethod(Security.class, "addProvider", int.class, Provider.class), bcProvider);
+
         if (!proxies.isEmpty()) {
             ResultHandle proxySupportClass = overallCatch.loadClassFromTCCL(DYNAMIC_PROXY_REGISTRY);
             ResultHandle proxySupport = overallCatch.invokeStaticMethod(

and it makes it work.

@sberyozkin
Copy link
Member Author

@zakkak Cool, let me experiment with the idea of a build item, might take a bit of time but I'm on it :-), thanks for the help

@sberyozkin
Copy link
Member Author

sberyozkin commented Feb 14, 2022

Hi @zakkak I've experimented with adding NativeImageAutoFeatureAugmentorBuildItem, with the idea being that individual extensions augment the feature as they need to and indeed this BC Cipher test works in Native now :-).
(I'm not sure if instead I should add for example NativeImageAutoFeatureAddSecurityProviderBuildItem and NativeImageAutoFeatureInsertSecurityProviderBuildItem as insert is required for BC JSSE - I'm not sure it will be flexible enough - but I can try if you would prefer it).

I have a question though, you suggested earlier:

So to resolve this we will need to move the Security.addProvider(new BouncyCastleProvider()); invocation out of the static initializer and place it in the generated io.quarkus.runner.AutoFeature.

So, now we add it in AutoFeature but I had to keep the code which records adding this provider in the static initializer, otherwise the JMV test fails. Calling Security.addProvider multiple times for the same provider is not a problem, it returns -1 if
the provider was already installed, so it is probably OK to have it called from AutoFeature and the static initializer ?

@zakkak
Copy link
Contributor

zakkak commented Feb 15, 2022

Hi @zakkak I've experimented with adding NativeImageAutoFeatureAugmentorBuildItem, with the idea being that individual extensions augment the feature as they need to and indeed this BC Cipher test works in Native now :-). (I'm not sure if instead I should add for example NativeImageAutoFeatureAddSecurityProviderBuildItem and NativeImageAutoFeatureInsertSecurityProviderBuildItem as insert is required for BC JSSE - I'm not sure it will be flexible enough - but I can try if you would prefer it).

The current approach seems fine to me.

What happens if you add the provider in the feature and insert it in the static initializer (for BC JSSE)?

I have a question though, you suggested earlier:

So to resolve this we will need to move the Security.addProvider(new BouncyCastleProvider()); invocation out of the static initializer and place it in the generated io.quarkus.runner.AutoFeature.

So, now we add it in AutoFeature but I had to keep the code which records adding this provider in the static initializer, otherwise the JMV test fails. Calling Security.addProvider multiple times for the same provider is not a problem, it returns -1 if the provider was already installed, so it is probably OK to have it called from AutoFeature and the static initializer ?

Yes, looking at your patch I was thinking the same. It looks OK to me but I'll also ask on GraalVM's slack.

@sberyozkin
Copy link
Member Author

@zakkak

What happens if you add the provider in the feature and insert it in the static initializer (for BC JSSE)?

I haven't tried yet but will do next :-)

@sberyozkin sberyozkin changed the title Support BouncyCastle ECDSA KeyPairGenerator and AES/CBC/PKCS7Padding Cipher Add BouncyCastle providers to generated AutoFeature Feb 15, 2022
@sberyozkin
Copy link
Member Author

@zakkak Hi, it actually works now for BC JSSE as well :-), so #17046 will get fixed - I added the code which inserts the BC JSSE (alongside BC) provider in the generated AutoFeature - the fact that the same insertProviderAt is attempted at the static init time makes no difference - the test enforces the BC, BCJSSE, SunJSSE sequence is returned, so if insertProviderAt was causing the duplicate entries then the test would've failed.

It does look like, given the code which has to be generated to support BC JSSE that this callback to AutoFeatureAugmentor makes sense, otherwise we'd need to introduce a new build item per this and other specific cases.

Let me try if may be BC JSSE FIPS can also be be fixed, and then I'll open for review

Thanks

@zakkak
Copy link
Contributor

zakkak commented Feb 15, 2022

Great work @sberyozkin .

While at it, it might be worth testing whether we can now get rid of -H:AdditionalSecurityProviders=org.bouncycastle.jce.provider.BouncyCastleProvider etc.

In my local tests after registrering the provider with the AutomaticFeature I didn't have to use -H:AdditionalSecurityProviders=org.bouncycastle.jce.provider.BouncyCastleProvider any more.

@sberyozkin
Copy link
Member Author

@zakkak

While at it, it might be worth testing whether we can now get rid of -H:AdditionalSecurityProviders=org.bouncycastle.jce.provider.BouncyCastleProvider etc.

Good point, indeed, I was able to remove it for org.bouncycastle.jce.provider.BouncyCastleProvider for both BCand BCJSSE cases, but I had to keep -H:AdditionalSecurityProviders=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider itself when dealing with BCJSSE - not sure why, I've tested it 3 times and it only works if BouncyCastleJsseProvideris also registered

@sberyozkin
Copy link
Member Author

Hey @zakkak, unfortunately adding BC JSSE FIPS to the feature does not work yet; well, it may work in the end, but I can't verify it since I'm getting the error at #14139, so for now I'm not adding the BC JSSE FIPS specific registration code (would be easy to do - nearly identical to the BC JSSE case).
Can you look at #14139 when you get a chance and see if we can try to workaround it somehow ? It is nearly there for a complete BC native support reopening :-).
In meantime, I'll open this PR for review, thanks

@sberyozkin sberyozkin marked this pull request as ready for review February 15, 2022 17:06
@sberyozkin sberyozkin requested review from zakkak and gsmet February 15, 2022 17:07
@quarkus-bot
Copy link

quarkus-bot bot commented Feb 15, 2022

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building 0dfc9ca

Status Name Step Failures Logs Raw logs
Gradle Tests - JDK 11 Windows Build Failures Logs Raw logs
✔️ JVM Tests - JDK 11
JVM Tests - JDK 17 Build Failures Logs Raw logs

Full information is available in the Build summary check run.

Failures

⚙️ Gradle Tests - JDK 11 Windows #

- Failing: integration-tests/gradle 

📦 integration-tests/gradle

io.quarkus.gradle.devmode.MultiSourceProjectDevModeTest.main line 22 - More details - Source on GitHub

org.awaitility.core.ConditionTimeoutException: Condition with lambda expression in io.quarkus.test.devmode.util.DevModeTestUtils that uses java.util.function.Supplier, java.util.function.Supplierjava.util.concurrent.atomic.AtomicReference, java.util.concurrent.atomic.AtomicReferencejava.lang.String, java.lang.Stringboolean was not fulfilled within 1 minutes.
	at org.awaitility.core.ConditionAwaiter.await(ConditionAwaiter.java:164)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:78)

⚙️ JVM Tests - JDK 17 #

- Failing: integration-tests/container-image/maven-invoker-way 

📦 integration-tests/container-image/maven-invoker-way

Failed to execute goal org.apache.maven.plugins:maven-invoker-plugin:3.2.2:run (integration-tests) on project quarkus-integration-test-container-image-invoker: 1 build failed. See console output above for details.

📦 integration-tests/container-image/maven-invoker-way/target/it/container-build-with-keycloak-default-realm

org.acme.security.openid.connect.NativeBearerTokenAuthenticationIT.testAdminAccess - More details - Source on GitHub

java.lang.RuntimeException: java.lang.IllegalStateException: Unable to determine the status of the running process. See the above logs for details
Caused by: java.lang.IllegalStateException: Unable to determine the status of the running process. See the above logs for details

org.acme.security.openid.connect.NativeBearerTokenAuthenticationIT.testAdminAccess - More details - Source on GitHub

java.lang.RuntimeException: java.lang.IllegalStateException: Unable to determine the status of the running process. See the above logs for details
Caused by: java.lang.IllegalStateException: Unable to determine the status of the running process. See the above logs for details

@quarkus-bot
Copy link

quarkus-bot bot commented Feb 16, 2022

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building 80bd519

Status Name Step Failures Logs Raw logs
Gradle Tests - JDK 11 Windows Build Failures Logs Raw logs
✔️ JVM Tests - JDK 11
JVM Tests - JDK 17 Build Failures Logs Raw logs

Full information is available in the Build summary check run.

Failures

⚙️ Gradle Tests - JDK 11 Windows #

- Failing: integration-tests/gradle 

📦 integration-tests/gradle

io.quarkus.gradle.devmode.MultiSourceProjectDevModeTest.main line 22 - More details - Source on GitHub

org.awaitility.core.ConditionTimeoutException: Condition with lambda expression in io.quarkus.test.devmode.util.DevModeTestUtils that uses java.util.function.Supplier, java.util.function.Supplierjava.util.concurrent.atomic.AtomicReference, java.util.concurrent.atomic.AtomicReferencejava.lang.String, java.lang.Stringboolean was not fulfilled within 1 minutes.
	at org.awaitility.core.ConditionAwaiter.await(ConditionAwaiter.java:164)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:78)

⚙️ JVM Tests - JDK 17 #

- Failing: extensions/reactive-routes/deployment 
! Skipped: extensions/agroal/deployment extensions/elytron-security-jdbc/deployment extensions/flyway/deployment and 164 more

📦 extensions/reactive-routes/deployment

io.quarkus.vertx.web.context.DuplicatedContextTest.testThatBlockingRoutesAreCalledOnDuplicatedContext line 63 - More details - Source on GitHub

java.net.SocketTimeoutException: Read timed out
	at java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:283)
	at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:309)

@sberyozkin
Copy link
Member Author

Test failures are not related

Copy link
Contributor

@zakkak zakkak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM thanks @sberyozkin

I'll leave the decision about whether the "generic" AutoFeatureAugmentor is welcome or not to the Quarkus team :)

@sberyozkin
Copy link
Member Author

Thanks @zakkak, yeah, I'll wait for Guillaume and others to comment

@zakkak
Copy link
Contributor

zakkak commented Feb 21, 2022

So, now we add it in AutoFeature but I had to keep the code which records adding this provider in the static initializer, otherwise the JMV test fails. Calling Security.addProvider multiple times for the same provider is not a problem, it returns -1 if the provider was already installed, so it is probably OK to have it called from AutoFeature and the static initializer ?

Yes, looking at your patch I was thinking the same. It looks OK to me but I'll also ask on GraalVM's slack.

Regarding this issue, Aleksandar Gradinac had a good idea:

"""
hmm, I think the two calls to addProvider could possibly be avoided by using build time initialization: you could use addProvider in a static initializer of some class, and then manually trigger the initialization of that class from the feature code before analysis (just using build time initialization won't work as it happens during analysis and we've already computed the services at that time)
"""

@sberyozkin
Copy link
Member Author

Hi @zakkak Thanks, so we indeed do the built time static initialization (via SecurityProviderRecorder).

and then manually trigger the initialization of that class from the feature code

But not sure about this one - as whatever is done in the SecurityProviderRecorder would be added to the global Quarkus static initialization code ?

addProvider/insertProvider for the same provider should be idempotent - the tests confirm it, so it should not be a problem if it is done twice...

@sberyozkin
Copy link
Member Author

Hey @zakkak I think it should be safe to backport it to 2.7.x so adding a backport label, @gsmet reminded about it. Adding a provider at the auto-feature level should be safe in 2.7.x, I hope

@quarkus-bot
Copy link

quarkus-bot bot commented Feb 26, 2022

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building b245996

Status Name Step Failures Logs Raw logs
Devtools Tests - JDK 17 Download Maven Repo ⚠️ Check → Logs Raw logs

@quarkus-bot
Copy link

quarkus-bot bot commented Mar 1, 2022

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building dd7be08

Status Name Step Failures Logs Raw logs
Native Tests - Messaging1 Download Maven Repo ⚠️ Check → Logs Raw logs

@gsmet
Copy link
Member

gsmet commented Mar 1, 2022

I'd like @stuartwdouglas to have a look at this one before we backport it.

@sberyozkin sberyozkin force-pushed the bc_keypair_ecdsa_xdh branch from dd7be08 to 2a3668f Compare March 7, 2022 18:44
@sberyozkin
Copy link
Member Author

Hi @stuartwdouglas @zakkak @gsmet Now a BC specific auto feature is optionally generated.

Have a look please and let me know what you think

@sberyozkin sberyozkin force-pushed the bc_keypair_ecdsa_xdh branch from 2a3668f to af17d0e Compare March 7, 2022 18:47
@quarkus-bot
Copy link

quarkus-bot bot commented Mar 7, 2022

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building af17d0e

Status Name Step Failures Logs Raw logs
✔️ JVM Tests - JDK 11
JVM Tests - JDK 11 Windows Build Failures Logs Raw logs
✔️ JVM Tests - JDK 17

Full information is available in the Build summary check run.

Failures

⚙️ JVM Tests - JDK 11 Windows #

- Failing: extensions/vertx-http/deployment 
! Skipped: core/test-extension/deployment extensions/agroal/deployment extensions/amazon-lambda-http/deployment and 308 more

📦 extensions/vertx-http/deployment

io.quarkus.vertx.http.http2.Http2Test.testHttp2EnabledSsl line 57 - More details - Source on GitHub

java.util.concurrent.ExecutionException: javax.net.ssl.SSLHandshakeException: Failed to create SSL connection
	at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:395)
	at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1999)

Copy link
Contributor

@zakkak zakkak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, other than two minor comments.

Thanks @sberyozkin !

Comment on lines 241 to 243
ClassCreator file = createBouncyCastleFeatureCreator(nativeImageClass);
MethodCreator beforeAn = createBeforeAnalysisMethod(file);
TryBlock overallCatch = beforeAn.tryBlock();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is common code in both if and else blocks, I would move it before the if-statement to avoid code duplication.

This would also remove the need for defining the createBeforeAnalysisMethod method.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @zakkak In both cases (here and in the other one you comment at below) it is conditional,

Optional<BouncyCastleJsseProviderBuildItem> bouncyCastleJsseProvider = getOne(bouncyCastleJsseProviders);
if (bouncyCastleJsseProvider.isPresent()) {
           
            ClassCreator file = createBouncyCastleFeatureCreator(nativeImageClass);
            MethodCreator beforeAn = createBeforeAnalysisMethod(file);
            TryBlock overallCatch = beforeAn.tryBlock();

            if (!bouncyCastleJsseProvider.get().isInFipsMode()) {
                //...
            } else {
                //...
            }
            completeBouncyCastleFeature(file, beforeAn, overallCatch);

        } else {
            Optional<BouncyCastleProviderBuildItem> bouncyCastleProvider = getOne(bouncyCastleProviders);
            if (bouncyCastleProvider.isPresent()) {
                
                ClassCreator file = createBouncyCastleFeatureCreator(nativeImageClass);
                MethodCreator beforeAn = createBeforeAnalysisMethod(file);
                TryBlock overallCatch = beforeAn.tryBlock();

                //...
                completeBouncyCastleFeature(file, beforeAn, overallCatch);
            }
        }

See, I can't move it the class creator code above the top if (and closing it outside it).
Am I missing something ?
Thanks

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I.e, there is a branch which allows for no BC or BC JSSE providers found at all

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zakkak I'll collapse both ifs

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zakkak I've done a small refactoring, hope it looks cleaner now, thanks

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, I missed the if-statement in the else body... Sorry for the noise

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zakkak Np at all, I still followed up with a minor refactoring, to avoid nested if inside the outer else which was not too cool, so thanks for your suggestion.

@gsmet
Copy link
Member

gsmet commented Mar 8, 2022

@sberyozkin if you want this one in 2.7.4.Final, I need it merged today. Thanks.

@sberyozkin sberyozkin force-pushed the bc_keypair_ecdsa_xdh branch from af17d0e to 8f86882 Compare March 8, 2022 12:33
@sberyozkin
Copy link
Member Author

@gsmet Thanks, I think I have addressed Foivos's comments, so if one more approval is added then it will make it

@quarkus-bot
Copy link

quarkus-bot bot commented Mar 8, 2022

Failing Jobs - Building 8f86882

Status Name Step Failures Logs Raw logs
Gradle Tests - JDK 11 Build Failures Logs Raw logs
Gradle Tests - JDK 11 Windows Build ⚠️ Check → Logs Raw logs

Full information is available in the Build summary check run.

Failures

⚙️ Gradle Tests - JDK 11 #

- Failing: integration-tests/gradle 

📦 integration-tests/gradle

io.quarkus.gradle.BeanInTestSourcesTest.testBasicMultiModuleBuild line 15 - More details - Source on GitHub

org.opentest4j.AssertionFailedError: 

expected: "SUCCESS"

io.quarkus.gradle.KotlinGRPCProjectBuildTest.testBasicMultiModuleBuild line 15 - More details - Source on GitHub

org.opentest4j.AssertionFailedError: 

expected: "SUCCESS"

io.quarkus.gradle.MultiModuleKotlinProjectBuildTest.testBasicMultiModuleBuild line 15 - More details - Source on GitHub

org.opentest4j.AssertionFailedError: 

expected: "SUCCESS"

io.quarkus.gradle.MultiSourceProjectTest.shouldRunTest line 16 - More details - Source on GitHub

org.opentest4j.AssertionFailedError: 

expected: "SUCCESS"

Copy link
Member

@gsmet gsmet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Failing tests do not include security so I don't think the failures are related.

@gsmet gsmet dismissed stuartwdouglas’s stale review March 8, 2022 18:10

Sergey changed the approach.

@gsmet gsmet merged commit 7fa3cb6 into quarkusio:main Mar 8, 2022
@quarkus-bot quarkus-bot bot added this to the 2.8 - main milestone Mar 8, 2022
@gsmet gsmet modified the milestones: 2.8 - main, 2.7.4.Final Mar 8, 2022
@sberyozkin sberyozkin deleted the bc_keypair_ecdsa_xdh branch March 8, 2022 21:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[native image] Bouncycastle JSSE fails with GraalVM 21.1
4 participants