quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.69k stars 2.65k forks source link

Generic Security Provider native image registration code is not complete #21099

Open sberyozkin opened 2 years ago

sberyozkin commented 2 years ago

Describe the bug

The current security provider registration code is limited in what it can do - it can only work for the default Sun providers which are already available - and it only registers them for reflection.

It does not work for providers like sun.security.pkcs11.SunPKCS11

Expected behavior

When a new provider is registered it should be added as a security provider if it is not already available - additionally it should be registered as an additional security provider in native image

Actual behavior

No response

How to Reproduce?

No response

Output of uname -a or ver

No response

Output of java -version

No response

GraalVM version (if different from Java)

No response

Quarkus version or git rev

No response

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

No response

Additional information

No response

malys commented 2 years ago

@sberyozkin Actual behavior

final Provider prototype = Security.getProvider("SunPKCS11");
return prototype.configure("--" + configuration);

This function return null (exclusively with the native build)

How to Reproduce? Fot testing, I use SoftHSM2 ([Windows](choco install softhsm), Linux, Tutorial). Use this code to reproduce it:

final Provider prototype = Security.getProvider("SunPKCS11");
return prototype.configure("--" + configuration);

Example of configuration

name=SoftHSM2
library=D:\\Developpement\\prog\\SoftHSM2\\lib\\softhsm2-x64.dll
slotListIndex=0
description=JCA Provider for Datavault

Output of uname -a or ver

Linux FR-DEV-L-094 4.19.104-microsoft-standard #1 SMP Wed Feb 19 06:37:35 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

and

Windows 10 Pro 2004

Output of java -version

openjdk version "17" 2021-09-14
OpenJDK Runtime Environment Temurin-17+35 (build 17+35)
OpenJDK 64-Bit Server VM Temurin-17+35 (build 17+35, mixed mode, sharing)

GraalVM version (if different from Java)

openjdk version "17.0.1" 2021-10-19
OpenJDK Runtime Environment GraalVM CE 21.3.0 (build 17.0.1+12-jvmci-21.3-b05)
OpenJDK 64-Bit Server VM GraalVM CE 21.3.0 (build 17.0.1+12-jvmci-21.3-b05, mixed mode, sharing

Quarkus version or git rev

2.3.1.Final

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

Apache Maven 3.8.3 (ff8e977a158738155dc465c6a97ffaf31982d739)

Additional information

malys commented 2 years ago

@sberyozkin have you enough information?

sberyozkin commented 2 years ago

@malys Thanks, this is sufficient, I think the problem is not confined to supporting this specific provider - if we can tune the code such that any 3rd party provider requiring no dedicated processing works in native then it will work for this provider as well

malys commented 2 years ago

Hi Sorry to insist but have you found time to think about a solution? Is it possible to have some visibility about the priority of this fix because depending on your position, I will deliver jar or native file? Thanks @sberyozkin,

sberyozkin commented 2 years ago

@malys Can you please try it with #25068 ?

sberyozkin commented 2 years ago

I'll look at manually testing it with SoftHSM2 as well

sberyozkin commented 2 years ago

I'm seeing https://github.com/oracle/graal/issues/2552 in native mode

sberyozkin commented 2 years ago

@zakkak Hi Foivos, can you please comment on what can be done to avoid https://github.com/oracle/graal/issues/2552, see also #25068. This issue can be reproduced once #25068 is merged as follows:

name = SoftHSM
library = /home/linuxbrew/.linuxbrew/lib/softhsm/libsofthsm2.so
slot = <generated-slot-number-goes-here>
attributes(generate, *, *) = {
   CKA_TOKEN = true
}
attributes(generate, CKO_CERTIFICATE, *) = {
   CKA_PRIVATE = false
}
attributes(generate, CKO_PUBLIC_KEY, *) = {
   CKA_PRIVATE = false
}

and then

quarkus.security.security-providers=SunPKCS11

and, in the endpoint code for now:

Provider configuredProvider = Security.getProvider("SunPKCS11").configure(pathToConfigFile);
Security.addProvider(configuredProvider);

will lead to https://github.com/oracle/graal/issues/2552.

Supporting it in native mode can make a difference for our FIPS story, likely to have providers like SunPKCS11-NSS-FIPS configured. (#25068 makes it easy to do it at the config level but it won't work in native for now).

Have a look please when you get a chance, thanks

sberyozkin commented 2 years ago

@zakkak FYI, just adding all the .pkcs11.wrapper classes for Reflection did not help, I see from https://github.com/oracle/graal/issues/2552 (and linked PRs) that more has to be done, I wonder if we can optionally do something like that in Quarkus via an extra native build item such as requesting j2pkcs.so be statically linked, etc. Ideally it would be done at the GraalVM level.

Also CC @galderz

zakkak commented 2 years ago

Hi @sberyozkin, I was on vacation. Adding this to my todo list for next week!

sberyozkin commented 2 years ago

@zakkak Hi Foivos, np at all, hope you've had a good time off; have a look please when you can have time, hopefully it can be an interesting issue to investigate

zakkak commented 2 years ago

Hi @sberyozkin I finally got to have a look at this. And it indeed looks like something that needs to be solved on the GraalVM side.

It looks like someone already tried fixing the underlying issue in https://github.com/oracle/graal/pull/3625 but the PR slipped through the cracks... I took that branch and rebased it on the latest graal (see https://github.com/zakkak/mandrel/tree/pkcs11) and ran the above test. I confirm that it gets past the linkage error but I am now getting:

Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_GENERAL_ERROR
    at com.oracle.svm.jni.JNIJavaCallWrappers.jniInvoke_VARARGS_PKCS11Exception_constructor_6117b76b7b85ffaea12ee4430bf7e4d602688744(JNIJavaCallWrappers.java:0)
    at sun.security.pkcs11.wrapper.PKCS11.C_Initialize(PKCS11.java)
    at sun.security.pkcs11.wrapper.PKCS11$SynchronizedPKCS11.C_Initialize(PKCS11.java:1631)
    at sun.security.pkcs11.wrapper.PKCS11.getInstance(PKCS11.java:166)
    at sun.security.pkcs11.SunPKCS11.<init>(SunPKCS11.java:338)
    ... 35 more

Since I am not familiar with any of these I would prefer you or someone more familiar continuing the investigation.

To build graal from my branch you will need to run:

git clone https://github.com/graalvm/mx --depth 1
./mx/mx fetch-jdk
export JAVA_HOME=<path-indicated-by-the-above-command>
git clone https://github.com/zakkak/nandrel --depth 1 --branch pkcs11
cd graal
mx --primary-suite-path substratevm --components='Native Image',LibGraal --native-images=native-image,lib:jvmcicompiler build

Then once the above is done you can use it to run your quarkus tests as follows:

GRAALVM_HOME=~/code/graal/sdk/latest_graalvm_home ./mvnw -Dnative -pl integration-tests/bouncycastle -Dtest-containers -Dstart-containers -Dnative.surefire.skip -Dformat.skip -Dno-descriptor-tests -Dlog.clean verify

Please let me know if there is anyway I can further help you with this.

Note: If you end up with a version you are happy with I can then follow up on getting https://github.com/oracle/graal/pull/3625 merged.

sberyozkin commented 2 years ago

Hi @zakkak Thanks for looking into it. Apologies I missed the comment. I'm not familiar with the C-level implementation details of Soft HSM, but it looks like it is exactly this error which is what you are seeing

https://stackoverflow.com/questions/67249557/ckr-general-error-when-configuring-sunpkcs11-with-softhsm.

Can you please give me a favor and try to re-run with -Djava.security.debug=sunpkcs11 - it may show some more info and also try setting an env SOFTHSM2_CONF to the config path location ? And if that does not help, replace Security.getProvider("SunPKCS11").configure(pathToConfigFile); with Security.getProvider("SunPKCS11").configure("--" + contentOfConfigFile); ?

Np at all if you won't have time, I can try it as some point as well.

Cheers

zakkak commented 2 years ago

Can you please give me a favor and try to re-run with -Djava.security.debug=sunpkcs11 - it may show some more info and also try setting an env SOFTHSM2_CONF to the config path location ?

Same issue

And if that does not help, replace Security.getProvider("SunPKCS11").configure(pathToConfigFile); with Security.getProvider("SunPKCS11").configure("--" + contentOfConfigFile); ?

I am not sure how to do that given that the config file is multiline. Shall I just seperate key=value pairs by space?

I tried

diff --git a/integration-tests/bouncycastle/src/main/java/io/quarkus/it/bouncycastle/BouncyCastleEndpoint.java b/integration-tests/bouncycastle/src/main/java/io/quarkus/it/bouncycastle/BouncyCastleEndpoint.java
index 2fc5053943..8bdb1efb93 100644
--- a/integration-tests/bouncycastle/src/main/java/io/quarkus/it/bouncycastle/BouncyCastleEndpoint.java
+++ b/integration-tests/bouncycastle/src/main/java/io/quarkus/it/bouncycastle/BouncyCastleEndpoint.java
@@ -4,6 +4,7 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.security.KeyFactory;
 import java.security.KeyPairGenerator;
+import java.security.Provider;
 import java.security.Security;
 import java.security.Signature;
 import java.security.spec.PKCS8EncodedKeySpec;
@@ -25,6 +26,21 @@ public class BouncyCastleEndpoint {
     @GET
     @Path("listProviders")
     public String listProviders() {
+        Provider configuredProvider = Security.getProvider("SunPKCS11")
+                .configure("--name = SoftHSM\n" +
+                "library = /usr/lib64/softhsm/libsofthsm.so\n" +
+                "slot = 1423586702\n" +
+                "attributes(generate, *, *) = {\n" +
+                "   CKA_TOKEN = true\n" +
+                "}\n" +
+                "attributes(generate, CKO_CERTIFICATE, *) = {\n" +
+                "   CKA_PRIVATE = false\n" +
+                "}\n" +
+                "attributes(generate, CKO_PUBLIC_KEY, *) = {\n" +
+                "   CKA_PRIVATE = false\n" +
+                "}\n");
+        Security.addProvider(configuredProvider);
+
         return Arrays.asList(Security.getProviders()).stream()
                 .filter(p -> (p.getName().equals("BC") || p.getName().equals("SunPKCS11")))
                 .map(p -> p.getName()).collect(Collectors.joining(","));

with no luck.

zakkak commented 1 month ago

@sberyozkin can you please have a look at ^^ to see if we can push this forward?

Thanks

geoand commented 3 weeks ago

@sberyozkin ^