A DESCRIPTION OF THE PROBLEM :
Our project uses a HSM with a PKCS11 interface and needs a truststore in the HSM to boot up (The HSM run a pkcs11 V2.4 interface). To check if the certificate is created before starting the project, we run a keytool command to list all certificate in the HSM. In JDK 17, we observe no issue but with the JDK 21, a IOException occured.
After researched the root cause, we found the error in the library libj2pkcs11 with the commit 83e6a4c for the ticket JDK-8255409. On the src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c file (same for windows), a check is done to know if the pkcs11 library supports the C_GetInterface function (implemented in PKcs11 V3.0) at line 182.
During the check the dlerror method is used to control if there are no error in the calling of the PKCS11 proprietary vendor library.
The dlerror method display all error that occurred from the last call of dlerror (see man for dlerror).
(from this point, the line number are describe with the file src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c in the commit 83e6a4c )
On the line 183, dlerror is never called if the C_GetInterface pointer is null because of the short-circuit evaluation (GetInterface pointer will be set to NULL for every PKCS11 interface implemented with a version lesser than 3).
On the line 192, dlerror is called again for the C_GetFunctionList dlsym call, but as the dlerror was never called after the dlsym for C_GetInterface, the line 192 reports an error related for the C_GetInterface even if the C_GetFunctionList dlsym call did not produce any error. As dlsym is not null, an exception is thrown and the PKCS11 library cannot be used.
Following the man for dlsym, dlerror shall be called before the test on the dlsym return pointer. Furthermore, dlsym can return the NULL value as a valid value (only the dlerror return value can differentiates errors from successes).
REGRESSION : Last worked in version 17.0.10
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
A keytool command is enough to reproduce the issue. We test with the following command:
keytool -v -keystore NONE -providername SunPKCS11-Proteccio -providerclass sun.security.pkcs11.SunPKCS11 -providerarg /opt/project/conf/pkcs11.cfg -storetype PKCS11 -list -alias s1as -storepass 12345678
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The expected result is the print in the console of any field of the certificate
ACTUAL -
keytool error: java.security.ProviderException: Initialization failed
java.security.ProviderException: Initialization failed
at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11.<init>(SunPKCS11.java:391)
at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11$1.run(SunPKCS11.java:126)
at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11$1.run(SunPKCS11.java:123)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:571)
at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11.configure(SunPKCS11.java:123)
at java.base/sun.security.tools.KeyStoreUtil.loadProviderByName(KeyStoreUtil.java:283)
at java.base/sun.security.tools.KeyStoreUtil.loadProviderByClass(KeyStoreUtil.java:316)
at java.base/sun.security.tools.keytool.Main.doCommands(Main.java:834)
at java.base/sun.security.tools.keytool.Main.run(Main.java:419)
at java.base/sun.security.tools.keytool.Main.main(Main.java:412)
Caused by: java.io.IOException: Symbol not found: C_GetInterface
at jdk.crypto.cryptoki/sun.security.pkcs11.wrapper.PKCS11.connect(Native Method)
at jdk.crypto.cryptoki/sun.security.pkcs11.wrapper.PKCS11.<init>(PKCS11.java:155)
at jdk.crypto.cryptoki/sun.security.pkcs11.wrapper.PKCS11.getInstance(PKCS11.java:186)
at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11.<init>(SunPKCS11.java:329)
... 9 more
CUSTOMER SUBMITTED WORKAROUND :
We test with success a fix that change the line 183 of the file p11_md.c (for unix) to:
if ((dlerror() == NULL) && (C_GetInterface != NULL)) {
from
if ((C_GetInterface != NULL) && (dlerror() == NULL)) {
FREQUENCY : always