带有加密提供程序的已签名模块化JAR无法链接到运行时映像

时间:2018-05-30 06:42:48

标签: java-9 jar-signing jigsaw java-module jlink

我试图使用jlink工具来构建java可执行文件。我是按照以下方式使用它的:

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

但是它给了我以下错误:

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

当我添加&#34; - ignore-signing-information&#34;选项,它构建我的可执行文件,但它给了我以下警告:

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

然后,当我执行已经构建的可执行文件时,我得到以下异常:

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)

我的问题是 - 有没有办法将签名的罐子用于&#34; jlink&#34;工具,或者有没有办法避免错误&#34;非Oracle JCE提供商可能没有链接到图像&#34;?

1 个答案:

答案 0 :(得分:1)

我知道它很旧,但我最近遇到了同样的问题。看起来它是 Oracle OpenJDK 的“独家功能”之一,就像 Alan Bateman 在评论中所说的那样。我测试了 Adopt 和 Liberica OpenJDK,虽然 jlink 仍然警告不支持签名的 jar,但没有运行时异常。


这是一个简单的测试,以防有人感兴趣。我使用moditect Maven 插件,它使用Maven toolchains 选择JDK 来构建运行时映像。

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(片段)

<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(片段)

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

结果

利比里亚和采用:

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

甲骨文:

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 bctest@1.0-SNAPSHOT/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

总结

除非您使用 Oracle JDK,否则请使用 --ignore-signing-information 并忽略相应的警告。如果您使用的是 Oracle JDK,则无法避免运行时异常,因为 JPMS 的编译时性质。 Java 模块中没有“提供的范围”这样的东西。因此,请考虑支持那些不会对其用户施加无意义限制的 OpenJDK 供应商。