Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

signed modular JAR with crypto provider cannot be linked into run-time image

I'm trying to use the jlink tool in order to build a java executable. I'm using it in the following way:

jlink.exe --module-path <path-to-modules> --add-modules <my-module-name> --output dist --launcher launch=org.demo/org.demo.Main --strip-debug --compress 2 --no-header-files --no-man-pages

but it gives me the following error:

Error: signed modular JAR <path-to-modules>\bcprov.jdk15on.jar is currently not supported, use --ignore-signing-information to suppress error

When I add the "--ignore-signing-information" option, it builds my executable fine, but it gives me the following warning:

WARNING: signed modular JAR <path-to-modules>\bcprov.jdk15on.jar is currently not supported

And then later on, when I execute the already built executable, I get the following exception:

org.apache.sshd.common.SshException: Failed (NoSuchProviderException) to execute: JCE cannot authenticate the provider BC
    at sshd.core/org.apache.sshd.common.future.AbstractSshFuture.verifyResult(Unknown Source)
    at sshd.core/org.apache.sshd.client.future.DefaultAuthFuture.verify(Unknown Source)
    at sshd.core/org.apache.sshd.client.future.DefaultAuthFuture.verify(Unknown Source)
Caused by: java.util.jar.JarException: Non-Oracle JCE providers may not be linked into the image,they must be provided as signed JAR files.
        at java.base/javax.crypto.ProviderVerifier.verify(Unknown Source)
        at java.base/javax.crypto.JceSecurity.verifyProvider(Unknown Source)
        at java.base/javax.crypto.JceSecurity.getVerificationResult(Unknown Source)
        at java.base/javax.crypto.JceSecurity.getInstance(Unknown Source)
        at java.base/javax.crypto.KeyAgreement.getInstance(Unknown Source)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

My question is - is there any way to use signed jars with the "jlink" tool, or is there any way to avoid the error "Non-Oracle JCE providers may not be linked into the image"?

like image 710
pinpinokio Avatar asked May 30 '18 06:05

pinpinokio


1 Answers

I know it's old, but I've ran into the same issue recently. Looks like it's one of "exclusive features" of Oracle OpenJDK, just like Alan Bateman said in comments. I tested Adopt and Liberica OpenJDK and while jlink still warns that signed jars aren't supported, there's no runtime exceptions.


Here's a simple test in case someone got interested. I use moditect Maven plugin, which uses Maven toolchains to select JDK to build runtime image.

Main.java

public class Main {

    public static void main(String[] args) {
        try {
            if (Security.getProvider("BC") == null) {
                Security.insertProviderAt(new BouncyCastleProvider(), 0);
            }

            for (final Provider provider : Security.getProviders()) {
                System.out.println("provider: " + provider.getName());
            }

            Cipher cipher = Cipher.getInstance("AES", "BC");
            System.out.println(cipher.getProvider().getName());
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | NoSuchProviderException e) {
            e.printStackTrace();
        }
    }
}

module-info.java

module bctest {

    requires org.bouncycastle.pkix;
    requires org.bouncycastle.provider;
}

~/.m2/toolchains.xml (fragment)

<toolchain>
    <type>jdk</type>
    <provides>
        <version>16</version>
        <vendor>liberica</vendor>
        <platform>win64</platform>
    </provides>
    <configuration>
        <jdkHome>%dir_path%\jdk16-win64-full-liberica</jdkHome>
    </configuration>
</toolchain>
<toolchain>
    <type>jdk</type>
    <provides>
        <version>16</version>
        <vendor>oracle</vendor>
        <platform>win64</platform>
    </provides>
    <configuration>
        <jdkHome>%dir_path%\jdk16-win64-std-oracle</jdkHome>
    </configuration>
</toolchain>
<toolchain>
    <type>jdk</type>
    <provides>
        <version>16</version>
        <vendor>adopt</vendor>
        <platform>win64</platform>
    </provides>
    <configuration>
        <jdkHome>%dir_path%\jdk16-win64-std-adopt</jdkHome>
    </configuration>
</toolchain>

pom.xml (fragment)

<dependencies>
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcpkix-jdk15on</artifactId>
        <version>${lib.bouncycastle.version}</version>
    </dependency>
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>${lib.bouncycastle.version}</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${plugin.compiler.version}</version>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
            </configuration>
        </plugin>
        <plugin>
            <!-- copy project JAR to modules directory -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>${plugin.jar.version}</version>
            <configuration>
                <outputDirectory>${bld.modulesDirectory}</outputDirectory>
            </configuration>
        </plugin>
        <plugin>
            <!-- copy all dependencies JAR to modules directory -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>${plugin.dependency.version}</version>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${bld.modulesDirectory}</outputDirectory>
                        <includeScope>runtime</includeScope>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.moditect</groupId>
            <artifactId>moditect-maven-plugin</artifactId>
            <version>${plugin.moditect.version}</version>
            <executions>
                <execution>
                    <id>create-runtime-image</id>
                    <phase>package</phase>
                    <goals>
                        <goal>create-runtime-image</goal>
                    </goals>
                    <configuration>
                        <!-- switch between verdors described in ~/.m2/toolchains.xml -->
                        <baseJdk>version=16,vendor=adopt,platform=win64</baseJdk>
                        <modulePath>
                            <!-- source modules (JARs) -->
                            <path>${bld.modulesDirectory}</path>
                        </modulePath>
                        <modules>
                            <module>bctest</module>
                            <module>jdk.crypto.cryptoki</module>
                        </modules>
                        <launcher>
                            <name>bctest</name>
                            <module>bctest/rootpack.Main</module>
                        </launcher>
                        <outputDirectory>${project.build.directory}/jrt</outputDirectory>
                        <compression>2</compression>
                        <!-- exclude signing info from runtime image, otherwise jlink refuses to create it -->
                        <ignoreSigningInformation>true</ignoreSigningInformation>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Result

Liberica and Adopt:

provider: SUN
provider: SunRsaSign
provider: SunEC
provider: SunJSSE
provider: SunJCE
provider: SunSASL
provider: JdkLDAP
provider: SunPKCS11
provider: BC
BC

Oracle:

provider: SUN
provider: SunRsaSign
provider: SunEC
provider: SunJSSE
provider: SunJCE
provider: SunSASL
provider: JdkLDAP
provider: SunPKCS11
provider: BC
Exception in thread "main" java.lang.SecurityException: JCE cannot authenticate the provider BC
        at java.base/javax.crypto.Cipher.getInstance(Cipher.java:722)
        at java.base/javax.crypto.Cipher.getInstance(Cipher.java:642)
        at [email protected]/rootpack.Main.main(Main.java:24)
Caused by: java.util.jar.JarException: Non-Oracle JCE providers may not be linked into the image,they must be provided as signed JAR files.
        at java.base/javax.crypto.ProviderVerifier.verify(ProviderVerifier.java:123)
        at java.base/javax.crypto.JceSecurity.verifyProvider(JceSecurity.java:189)
        at java.base/javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:217)
        at java.base/javax.crypto.Cipher.getInstance(Cipher.java:718)
        ... 2 more

Summary

Unless you're using Oracle JDK, use --ignore-signing-information and ignore corresponding warning. If you're using Oracle JDK, there's no way to avoid runtime exception, because of compile-time nature of JPMS. There's no such thing as "provided scope" in Java modules. So, consider supporting OpenJDK vendors those do not place nonsense restrictions on their users.

like image 89
enzo Avatar answered Oct 11 '22 15:10

enzo