RFD: Security Providers Filter (JEP)

Francisco Ferrari Bihurriet fferrari at redhat.com
Mon Oct 21 15:22:24 UTC 2024


On 10/18/24 20:55, Martin Balao wrote:
> Our understanding is that in such an event the Filter would be
> initialized when the ClassLoader does JAR verification. If this is the
> case, programmatically defining a Filter in the signed JAR should not
> work. @Francisco will create a proof-of-concept to confirm this
> hypothesis in the coming days.
> 
Hi Sean,

I confirmed it, programmatically defining a Filter in a signed JAR
doesn't work (full test at the end of this email). In such cases, the
Filter initialization occurs at the following point:

java.lang.Exception: Stack trace
    at java.base/sun.security.jca.ProvidersFilter.<clinit>(ProvidersFilter.java:681)
    at java.base/java.security.Provider$Service.computeSvcAllowed(Provider.java:2807)
    at java.base/java.security.Provider$ServicesMap$ServicesMapImpl.putService(Provider.java:1099)
    at java.base/java.security.Provider.putService(Provider.java:2252)
    at java.base/sun.security.provider.Sun.putEntries(Sun.java:75)
    at java.base/sun.security.provider.Sun.<init>(Sun.java:61)
    at java.base/sun.security.jca.ProviderConfig.getProvider(ProviderConfig.java:183)
    at java.base/sun.security.jca.ProviderList.getProvider(ProviderList.java:271)
    at java.base/sun.security.jca.ProviderList.getIndex(ProviderList.java:301)
    at java.base/sun.security.jca.ProviderList.getProviderConfig(ProviderList.java:285)
    at java.base/sun.security.jca.ProviderList.getProvider(ProviderList.java:291)
    at java.base/sun.security.jca.Providers.startJarVerification(Providers.java:110)
    at java.base/sun.security.util.SignatureFileVerifier.<init>(SignatureFileVerifier.java:110)
    at java.base/java.util.jar.JarVerifier.processEntry(JarVerifier.java:301)
    at java.base/java.util.jar.JarVerifier.update(JarVerifier.java:232)
    at java.base/java.util.jar.JarFile.initializeVerifier(JarFile.java:760)
    at java.base/java.util.jar.JarFile.getInputStream(JarFile.java:858)
    at java.base/jdk.internal.loader.URLClassPath$JarLoader$2.getInputStream(URLClassPath.java:837)
    at java.base/jdk.internal.loader.Resource.cachedInputStream(Resource.java:77)
    at java.base/jdk.internal.loader.Resource.getByteBuffer(Resource.java:163)
    at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:853)
    at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:578)
    at java.base/java.lang.Class.forName(Class.java:557)
    at java.base/sun.launcher.LauncherHelper.loadMainClass(LauncherHelper.java:841)
    at java.base/sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:736)

> We agree that throwing an exception in such a case would be ideal.
> However, this type of change —as we see it— involves a specification
> change in System::setProperty/Security::setProperty as that's the only
> interface to set a Filter value programmatically. We are open to having
> this discussion.
> 
> Another alternative would be to reserve the property in
> System::setProperty/Security::setProperty and throw an exception
> irrespective of the Filter status. We think that setting the Filter
> programmatically should not be recommended for general use. However,
> this would prevent advanced users that know how things are initialized
> from benefiting.

__ jar_signing_test.sh _________________________________________________

#!/usr/bin/env bash
export JAVA_HOME="$(realpath build/*/images/jdk)"
[ -d "$JAVA_HOME" ] || exit 1

echo "Creating jar files..."
cat <<'EOF' >Main.java
import javax.crypto.Cipher;
import java.security.NoSuchAlgorithmException;

public final class Main {
    public static void main(String[] args) throws Exception {
        System.setProperty("jdk.security.providers.filter",
                "*.Cipher.*/CBC/*; !*.Cipher.*; *");
        // Allowed
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        cipher.getProvider();
        // Denied
        try {
            cipher = Cipher.getInstance("AES/ECB/NoPadding");
            throw new Error("Should have thrown (denied)!");
        } catch (NoSuchAlgorithmException expected) {}
        System.out.println("The filter is working properly.");
    }
}
EOF
$JAVA_HOME/bin/javac Main.java
$JAVA_HOME/bin/jar cfe unsigned.jar Main Main.class || exit 1
$JAVA_HOME/bin/jar cfe signed.jar Main Main.class
$JAVA_HOME/bin/keytool -keystore ks -storepass testpwd      \
    -keypass testpwd -dname CN=test -alias test -genkeypair \
    -keyalg EC &>/dev/null
$JAVA_HOME/bin/jarsigner -keystore ks -storepass testpwd \
    signed.jar test &>/dev/null || exit 1
rm -f ks Main.class Main.java

echo -e "\nUnsigned jar file\n================="
$JAVA_HOME/bin/java -Djava.security.debug=jca -jar unsigned.jar 2> \
    >(grep -m1 ^ProvidersFilter)

echo -e "\nSigned jar file\n==============="
$JAVA_HOME/bin/java -Djava.security.debug=jca -jar signed.jar 2> \
    >(grep '^ProvidersFilter\|java\.lang\.Error')

rm -f signed.jar unsigned.jar
unset JAVA_HOME
________________________________________________________________________

__ OUTPUT ______________________________________________________________

Creating jar files...

Unsigned jar file
=================
ProvidersFilter: Parsing: *.Cipher.*/CBC/*; !*.Cipher.*; *
The filter is working properly.

Signed jar file
===============
ProvidersFilter: No filter
Exception in thread "main" java.lang.Error: Should have thrown (denied)!
________________________________________________________________________

Regards,
-- 
Francisco



More information about the security-dev mailing list