IllegalAccessException in apksigner with SunPKCS11 on Debian 13 / Java 21

On Debian 13 (possibly due to Java 21?), signing with PKCS#11 no longer works.

Steps to reproduce

  • Pre-create the private key and certificate on the Nitrokey HSM. See the workaround described in #1312.
  • fdroid init
  • Edit the config.yml to set the repo_keyalias, keystore: NONE, keystorepass and the other relevant options
  • fdroid update

System info

  • Debian 13 (Trixie)
  • Java 21 (from apt)
  • fdroidserver 2.4.2 (from stable apt, NO backport)

Log

The output of fdroid update:

2025-12-30 20:06:18,420 INFO: Creating signed index with this key (SHA256):
2025-12-30 20:06:18,420 INFO: CC AA FF EE
2025-12-30 20:07:12,758 CRITICAL: Failed to sign repo/entry.jar: Exception in thread "main" java.lang.IllegalAccessException: class com.android.apksigner.ApkSignerTool$ProviderInstallSpec cannot access class sun.security.pkcs11.SunPKCS11 (in module jdk.crypto.cryptoki) because module jdk.crypto.cryptoki does not export sun.security.pkcs11 to unnamed module @2f2c9b19
        at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:394)
        at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:714)
        at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:495)
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486)
        at com.android.apksigner.ApkSignerTool$ProviderInstallSpec.installProvider(ApkSignerTool.java:1249)
        at com.android.apksigner.ApkSignerTool$ProviderInstallSpec.access$200(ApkSignerTool.java:1217)
        at com.android.apksigner.ApkSignerTool.sign(ApkSignerTool.java:351)
        at com.android.apksigner.ApkSignerTool.main(ApkSignerTool.java:94)

Workarounds

I ran into the same problem while trying to sign a single APK manually with apksigner. Here is how I got it to work.

It works, but it feels hacky, so I am very open to better ideas. Also, I am not sure if this is an intended change in Java 21, or if this should be reported as a bug upstream?

# depending on which apksigner you want
export JAR="${HOME}/Android/Sdk/build-tools/35.0.0/lib/apksigner.jar" # source: Android SDK
export JAR="/usr/share/java/apksigner.jar" # source: apt

sudo java --add-exports jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED -jar ${JAR} sign --provider-class sun.security.pkcs11.SunPKCS11 --provider-arg opensc-fdroid.cfg --ks NONE --ks-type PKCS11 --ks-pass stdin --ks-key-alias ${KEY_ALIAS} --in ${APK_IN} --out ${APK_OUT}

Important additions:

  • --add-exports jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED
  • Invoking apksigner.jar instead of apksigner (the shell script that ships with the Android SDK)