ebourg / jsign

Java implementation of Microsoft Authenticode for signing Windows executables, installers & scripts
https://ebourg.github.io/jsign
Apache License 2.0
259 stars 108 forks source link

NullPointerException with PKCS11 and Java 11 #124

Closed cxn-sjuhasz closed 1 year ago

cxn-sjuhasz commented 2 years ago

We have an issue, where signing through an entrust ncipher HSM works on java8, but fails on java11, with a lovely nullpointer. The setup and everything is the same. The HSM is used as a tokenizer.

myuser@myhost:~/jsign$ /data/apps/signerjava11/bin/java -jar jsign-4.0.jar --keystore /opt/nfast/pkcs11.cfg --storetype PKCS11 --alias mykey --storepass RANDOMPASSWORD --tsaurl http://timestamp.comodoca.com/authenticode mylittle.exe
jsign: Couldn't sign mylittle.exe
java.security.ProviderException: Failed to create a SunPKCS11 provider from the configuration /opt/nfast/pkcs11.cfg
    at net.jsign.ProviderUtils.createSunPKCS11Provider(ProviderUtils.java:52)
    at net.jsign.SignerHelper.build(SignerHelper.java:309)
    at net.jsign.SignerHelper.sign(SignerHelper.java:500)
    at net.jsign.JsignCLI.execute(JsignCLI.java:116)
    at net.jsign.JsignCLI.main(JsignCLI.java:40)
Caused by: java.lang.NullPointerException
    at java.base/java.lang.reflect.Method.invoke(Method.java:559)
    at net.jsign.ProviderUtils.createSunPKCS11Provider(ProviderUtils.java:45)
    ... 4 more
Try `java -jar jsign.jar --help' for more information.

myuser@myhost:~/jsign$ /data/apps/signerjava11/bin/java -version
java version "11.0.11" 2021-04-20 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.11+9-LTS-194)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.11+9-LTS-194, mixed mode)

myuser@myhost:~/jsign$ cat /opt/nfast/pkcs11.cfg
name = ncipher
library = /opt/nfast/toolkits/pkcs11/libcknfast.so
slotListIndex = 0

myuser@myhost:~/jsign$ file /opt/nfast/toolkits/pkcs11/libcknfast.so
/opt/nfast/toolkits/pkcs11/libcknfast.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, stripped

myuser@myhost:~/jsign$ /data/apps/signerjava/bin/java -jar jsign-4.0.jar --keystore /opt/nfast/pkcs11.cfg --storetype PKCS11 --alias mykey --storepass RANDOMPASSWORD --tsaurl http://timestamp.comodoca.com/authenticode mylittle.exe
Adding Authenticode signature to mylittle.exe

myuser@myhost:~/jsign$ /data/apps/signerjava/bin/java -version
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)

myuser@myhost:~/jsign$ uname -a
Linux myhost 5.4.0-97-generic #110-Ubuntu SMP Thu Jan 13 18:22:13 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

myuser@myhost:~/jsign$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.4 LTS"
ebourg commented 2 years ago

That's the OpenJDK 11 package from Ubuntu 20.04, or from another source?

cxn-sjuhasz commented 2 years ago

oracle java SE jdk - both

myuser@myhost:/data/apps/signerjava$ cat release 
JAVA_VERSION="1.8.0_144"
OS_NAME="Linux"
OS_VERSION="2.6"
OS_ARCH="amd64"
BUILD_TYPE="commercial"

myuser@myhost:/data/apps/signerjava11$ cat release 
BUILD_TYPE="commercial"
IMPLEMENTOR="Oracle Corporation"
IMPLEMENTOR_VERSION="18.9"
JAVA_VERSION="11.0.11"
JAVA_VERSION_DATE="2021-04-20"
OS_ARCH="x86_64"
OS_NAME="Linux"
cxn-sjuhasz commented 2 years ago

But it is reproducible with openjdk-11-jdk-headless ubuntu package as well.

ebourg commented 2 years ago

Ok, I'll try to reproduce it. At first glance it looks like Security.getProvider("SunPKCS11") returns null, I'm not sure to understand why.

cxn-sjuhasz commented 2 years ago

If you give me some prepped log config or any other way to force more info/stacktrace out of it, i can do it for you. Afaik the PKCS11 workflow works with other java applications, like plain jarsigner or install4j.

ebourg commented 1 year ago

Ok, I just installed a fresh Ubuntu VM, with the openjdk-11-jre-headless package from Ubuntu I get:

root@ubuntu:~# java -version
openjdk version "11.0.17" 2022-10-18
OpenJDK Runtime Environment (build 11.0.17+8-post-Ubuntu-1ubuntu220.04)
OpenJDK 64-Bit Server VM (build 11.0.17+8-post-Ubuntu-1ubuntu220.04, mixed mode, sharing)

root@ubuntu:~# java -jar jsign-4.0.jar --keystore pkcs11.cfg --storetype PKCS11 --alias mykey --storepass password application.exe
jsign: Couldn't sign application.exe
java.security.ProviderException: Failed to create a SunPKCS11 provider from the configuration pkcs11.cfg
        at net.jsign.ProviderUtils.createSunPKCS11Provider(ProviderUtils.java:52)
        at net.jsign.SignerHelper.build(SignerHelper.java:309)
        at net.jsign.SignerHelper.sign(SignerHelper.java:500)
        at net.jsign.JsignCLI.execute(JsignCLI.java:116)
        at net.jsign.JsignCLI.main(JsignCLI.java:40)
Caused by: java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at net.jsign.ProviderUtils.createSunPKCS11Provider(ProviderUtils.java:45)
        ... 4 more
Caused by: java.security.ProviderException: Library /opt/nfast/toolkits/pkcs11/libcknfast.so does not exist
        at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11.<init>(SunPKCS11.java:312)
        at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11$1.run(SunPKCS11.java:115)
        at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11$1.run(SunPKCS11.java:112)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11.configure(SunPKCS11.java:112)
        ... 9 more
Try `java -jar jsign.jar --help' for more information.

The error is expected since libcknfast.so isn't installed, but at least the stacktrace runs through SunPKCS11, so Security.getProvider("SunPKCS11") didn't return null.

With the Oracle JDK 11 I get this:

root@ubuntu:~# /usr/lib/jvm/jdk-11/bin/java -version
java version "11.0.17" 2022-10-18 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.17+10-LTS-269)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.17+10-LTS-269, mixed mode)

root@ubuntu:~# /usr/lib/jvm/jdk-11/bin/java -jar jsign-4.0.jar --keystore pkcs11.cfg --storetype PKCS11 --alias mykey --storepass password application.exe
jsign: Couldn't sign application.exe
java.security.ProviderException: Failed to create a SunPKCS11 provider from the configuration pkcs11.cfg
        at net.jsign.ProviderUtils.createSunPKCS11Provider(ProviderUtils.java:52)
        at net.jsign.SignerHelper.build(SignerHelper.java:309)
        at net.jsign.SignerHelper.sign(SignerHelper.java:500)
        at net.jsign.JsignCLI.execute(JsignCLI.java:116)
        at net.jsign.JsignCLI.main(JsignCLI.java:40)
Caused by: java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at net.jsign.ProviderUtils.createSunPKCS11Provider(ProviderUtils.java:45)
        ... 4 more
Caused by: java.security.ProviderException: Library /opt/nfast/toolkits/pkcs11/libcknfast.so does not exist
        at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11.<init>(SunPKCS11.java:302)
        at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11$1.run(SunPKCS11.java:116)
        at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11$1.run(SunPKCS11.java:113)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11.configure(SunPKCS11.java:113)
        ... 9 more
Try `java -jar jsign.jar --help' for more information.

So the same result.

I've edited /usr/lib/jvm/java-11-openjdk-amd64/conf/security/java.security and commented out the SunPKCS11 line:

#
# List of providers and their preference orders (see above):
#
security.provider.1=SUN
security.provider.2=SunRsaSign
security.provider.3=SunEC
security.provider.4=SunJSSE
security.provider.5=SunJCE
security.provider.6=SunJGSS
security.provider.7=SunSASL
security.provider.8=XMLDSig
security.provider.9=SunPCSC
security.provider.10=JdkLDAP
security.provider.11=JdkSASL
#security.provider.12=SunPKCS11

and now I get:

root@ubuntu:~# java -jar jsign-4.0.jar --keystore pkcs11.cfg --storetype PKCS11 --alias mykey --storepass password application.exe
jsign: Couldn't sign application.exe
java.security.ProviderException: Failed to create a SunPKCS11 provider from the configuration pkcs11.cfg
        at net.jsign.ProviderUtils.createSunPKCS11Provider(ProviderUtils.java:52)
        at net.jsign.SignerHelper.build(SignerHelper.java:309)
        at net.jsign.SignerHelper.sign(SignerHelper.java:500)
        at net.jsign.JsignCLI.execute(JsignCLI.java:116)
        at net.jsign.JsignCLI.main(JsignCLI.java:40)
Caused by: java.lang.NullPointerException
        at java.base/java.lang.reflect.Method.invoke(Method.java:559)
        at net.jsign.ProviderUtils.createSunPKCS11Provider(ProviderUtils.java:45)
        ... 4 more
Try `java -jar jsign.jar --help' for more information.

Which is the same error you got.

Could you check if SunPKCS11 is enabled in your java.security file?

cxn-sjuhasz commented 1 year ago

It is enabled, there is where the config is referred for the library.

security.provider.12=SunPKCS11 /opt/nfast/pkcs11.cfg
ebourg commented 1 year ago

It's there but it was modified. Could try with just:

security.provider.12=SunPKCS11
cxn-sjuhasz commented 1 year ago

I could, but that way i would get error with accessing the library for nfast.

cxn-sjuhasz commented 1 year ago

Lol, it works, i made a prepped java11 for it. With original SunPKCS11 line.

myuser@myhost:~$ ~/signerjava11/bin/java -jar jsign-4.2.jar --keystore /opt/nfast/pkcs11.cfg --storetype PKCS11 --alias mykey --storepass RANDOMPASSWORD --tsaurl http://timestamp.comodoca.com/authenticode putty.exe 
Adding Authenticode signature to putty.exe

myuser@myhost:~$ ~/signerjava11/bin/jarsigner -tsa http://timestamp.digicert.com -keystore NONE -storetype PKCS11 -storepass RANDOMPASSWORD -sigalg SHA256withRSA commons-math-2.2.jar mykey
jar signed.

Warning: 
POSIX file permission and/or symlink attributes detected. These attributes are ignored when signing and are not protected by the signature.
The signer certificate will expire on 2024-04-29.
The timestamp will expire on 2031-11-10.

Duplicating the provider line works!!

security.provider.12=SunPKCS11
security.provider.13=SunPKCS11 /opt/nfast/pkcs11.cfg
ebourg commented 1 year ago

Great! Indeed when a configuration file is added after security.provider.12=SunPKCS11 in java.security, the name of the provider is no longer "SunPKCS11" but the one defined by the name attribute in the configuration file. That's why Security.getProvider("SunPKCS11") returned null.

I'll add an explicit warning if this happens.