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

1

6

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"?

Olwen answered 30/5, 2018 at 6:42 Comment(2)
There is no support in Oracle's JDK for linking 3rd party crypto into a run-time image. You'll need to leave that on the class path or module path.Terti
@AlanBateman "You'll need to leave that on the class path or module path" - but how do I do that? JLink requires from me to give it all the modules that my program uses in order to produce executable and then it includes them in the generated package ... Is there some option like "jlink.exe --classpath" where I put automatic modules that I don't recompile? Or maybe "jlink.exe --exclude-module-from-final-executable". The reason I recompiled the crypto module(and added module-info.java in it) was because jlink was telling me "Error: automatic module cannot be used with jlink"...Olwen
T
1

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.

Toyatoyama answered 8/7, 2021 at 4:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.