猿问

KeyStore.load() 因“无效的密钥库格式”而失败

在执行 keystore.load() 方法时,下面的代码每次都会出现“无效的密钥库格式”的 IOException。该文件已成功从 .jar 文件加载。在 Windows 10 专业版上使用 Java 1.8。Maven 用于编译和组装 jar 文件,然后一起 war 并作为 war 文件部署到 JBOSS 服务器。我试过 .getInstance 和 getDefault() 也有同样的错误。


InputStream stream;

stream = Thread.currentThread().getContextClassLoader()

    .getResourceAsStream("cacerts.jks");

if (stream == null) {

    stream = CustomTrustManager.class.getClassLoader()

        .getResourceAsStream("cacerts.jks");

}

if(stream == null) {

    Log.error("Unable to load cacerts.jks. This is needed to make HTTPS connections to internal servers.");

    throw new NotFoundException();

}


KeyStore myTrustStore = KeyStore.getInstance("JKS");

myTrustStore.load(stream, "xxxxx".toCharArray());

“cacerts.jks”文件是使用以下命令从自签名服务器证书“server1.crt”文件生成的:


keytool -v -import -alias devserver -file server1.crt -keystore cacerts.jks

这成功完成并命令:


keytool -list -keystore cacerts.jks

Keystore type: JKS

Keystore provider: SUN


Your keystore contains 1 entry


devserver, Aug 15, 2019, trustedCertEntry,

Certificate fingerprint (SHA1): F6:7F:C9:95:0E:B8:59:07:24:23:67:93:43:B2:C9:AA:CD:5B:AF:68

显示密钥库文件没有问题。我浏览了许多 StackOverflow 文章,但没有一篇指出问题的解决方案。在调试模式下,资源加载后 InputStream 具有以下格式。我假设从 .jar 文件加载 ZipFile 类型是正常的。

感谢任何有关如何成功加载密钥库文件的见解。谢谢



慕码人2483693
浏览 469回答 4
4回答

偶然的你

二进制 JKS 文件可能被 Maven 资源插件过滤,导致文件损坏,这是一个很常见的问题:Maven 在构建期间复制到 Java 资源目录时损坏 WAV 文件Maven 在构建 jar 时损坏 source/main/resources 中的二进制文件移动到资源文件夹时生成的证书停止工作二进制文件基本上被视为文本文件,因此 jar 中的文件以 UTF-8 字符 ( 0xEFBFBDEFBFBD) 而不是 JKS 的幻数 ( 0xFEEDFEED) 开头。资源插件文档包含一个明确的警告:不要过滤带有图像等二进制内容的文件!这很可能会导致损坏的输出。可能的解决方案是:将资源文件夹拆分为一个已过滤的文件夹和一个未过滤的文件夹全局禁用对扩展名为 .jks 的文件的过滤

jeck猫

确保避免过滤您的密钥库文件 jks喜欢<resources>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <resource>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <directory>src/main/resources</directory>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <filtering>true</filtering>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <excludes>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <exclude>**/*.jks</exclude>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </excludes>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </resource>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <resource>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <directory>src/main/resources</directory>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <filtering>false</filtering>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <includes>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <include>**/*.jks</include>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </includes>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </resource>&nbsp; &nbsp; &nbsp; &nbsp; </resources>

波斯汪

二进制文件基本上被视为文本文件,因此 jar 中的文件以 UTF-8 字符 (0xEFBFBDEFBFBD) 开头,而不是 JKS 的幻数 (0xFEEDFEED)。我在 pom.xml 文件的属性部分添加了这两行<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>它完成了工作

海绵宝宝撒

免责声明:这还不是一个完整的答案,但我需要一个与 OP 讨论的工具。如果这没有导致解决方案,我将再次删除答案。我在这样的 POJO 中复制了你的情况:$ openssl req -new -newkey rsa:4096 -x509 -sha256 -days 365 -nodes -out MyCertificate.crt -keyout MyKey.key(answer all questions with RETURN = accept defaults)$ keytool -v -import -alias devserver -file MyCertificate.crt -keystore src/main/resources/cacerts.jks -storetype JKSEnter keystore password:&nbsp; testtestRe-enter new password: testtest(...)Trust this certificate? [no]:&nbsp; yesCertificate was added to keystore[Storing src/main/resources/cacerts.jks]$ keytool -list -keystore src/main/resources/cacerts.jksEnter keystore password:&nbsp; testtestKeystore type: JKSKeystore provider: SUNYour keystore contains 1 entrydevserver, 24.08.2019, trustedCertEntry,Certificate fingerprint (SHA-256): A2:E1:49:FB:9C:26:6B:8A:21:45:A4:AA:F4:86:A0:A7:82:B8:08:BE:75:A6:BF:E8:F5:13:9E:31:23:8E:B0:71现在在 Maven JAR 模块中创建一个类似于 OP 所示代码的类:package de.scrum_master.stackoverflow;import java.io.IOException;import java.io.InputStream;import java.security.KeyStore;import java.security.KeyStoreException;import java.security.NoSuchAlgorithmException;import java.security.cert.CertificateException;public class CustomTrustManager {&nbsp; public static void main(String[] args) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {&nbsp; &nbsp; InputStream stream;&nbsp; &nbsp; stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("cacerts.jks");&nbsp; &nbsp; System.out.println(stream);&nbsp; &nbsp; if (stream == null) {&nbsp; &nbsp; &nbsp; stream = CustomTrustManager.class.getClassLoader().getResourceAsStream("cacerts.jks");&nbsp; &nbsp; }&nbsp; &nbsp; if(stream == null) {&nbsp; &nbsp; &nbsp; System.out.println("Unable to load cacerts.jks. This is needed to make HTTPS connections to internal servers.");&nbsp; &nbsp; &nbsp; throw new RuntimeException("Keystore not found");&nbsp; &nbsp; }&nbsp; &nbsp; KeyStore myTrustStore = KeyStore.getInstance("JKS");&nbsp; &nbsp; myTrustStore.load(stream, "testtest".toCharArray());&nbsp; &nbsp; System.out.println("Keystore loaded");&nbsp; }}现在构建项目并mvn clean package运行它:$ java -cp target/my-sample-1.0-SNAPSHOT.jar de.scrum_master.stackoverflow.CustomTrustManagersun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@3d4eac69Keystore loaded所以基本上你的方法应该有效。如果没有,它可以连接到类加载(但我不这么认为,因为密钥存储似乎很好),我在你的调用堆栈中看到的 AspectJ(或者更确切地说只是 Spring AOP)的东西(也不太可能),您自己的自定义信任管理器或您的“riskmeter”类所做的任何事情。请检查你在你的应用程序中使用的完全相同的密钥库是否像我的例子一样从一个简单的 JAR 中工作,没有容器或其他花哨的东西。如果是这样,您就知道问题不是您的密钥库。那么请在这里提供一些反馈。
随时随地看视频慕课网APP

相关分类

Java
我要回答