【问题标题】:TrustStore fails to init but KeyStore successfulTrustStore 无法初始化,但 KeyStore 成功
【发布时间】:2023-04-03 03:55:01
【问题描述】:

我正在尝试配置 Tomcat,以便我的 Web 应用程序可以使用 LDAPS。在 UAT 服务器上一切正常,但由于某种原因,生产服务器无法初始化信任库。 我已经打开调试(通过-Djavax.net.debug=all),错误是:

默认上下文初始化失败:java.io.IOException:密钥库被篡改,或密码不正确

我 100% 确定密码正确,因为我已经运行了 keytool 并列出了信任库的内容,并从工作的 UAT 服务器获取了相同的文件。

作为一个实验,我将 Tomcat 配置为对密钥库和信任库使用相同的存储文件(我意识到这不是典型的设置,但据我了解,文件格式等是相同的,因此它们都应该加载):

-Djavax.net.ssl.trustStorePassword=xxx -Djavax.net.ssl.trustStore=C:\Program Files\Apache Software Foundation\Tomcat 7.0\bin\.keystore -Djavax.net.ssl.keyStorePassword=xxx -Djavax.net.ssl.keyStore=C:\Program Files\Apache Software Foundation\Tomcat 7.0\bin\.keystore

密钥库有效:

keyStore 是:C:\Program Files\Apache Software Foundation\Tomcat 7.0\bin.keystore
keyStore 类型是:jks
keyStore 提供者是:
初始化密钥库
SunX509 类型的初始化密钥管理器 ***
找到 : tomcat 的密钥

虽然信任库失败.. 对于相同的文件和密码!

trustStore 是:C:\Program Files\Apache Software Foundation\Tomcat 7.0\bin.keystore
trustStore 类型是:jks
trustStore 提供者是:
初始化信任库
默认上下文初始化失败:java.io.IOException:密钥库被篡改,或密码不正确

从 Web 应用程序中,堆栈跟踪有更多详细信息(我不确定它是否有帮助。我研究了 TrustManagerFactoryImpl 的 java 源代码并将其与日志记录匹配,但它没有解释行为)

javax.naming.CommunicationException: <ldap url>:636 [Root exception is java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext)]
    at com.sun.jndi.ldap.Connection.<init>(Unknown Source)
    at com.sun.jndi.ldap.LdapClient.<init>(Unknown Source)
    at com.sun.jndi.ldap.LdapClient.getInstance(Unknown Source)
    at com.sun.jndi.ldap.LdapCtx.connect(Unknown Source)
    at com.sun.jndi.ldap.LdapCtx.<init>(Unknown Source)
    at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(Unknown Source)
    at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(Unknown Source)
    at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(Unknown Source)
    at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(Unknown Source)
    at javax.naming.spi.NamingManager.getInitialContext(Unknown Source)
    at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source)
    at javax.naming.InitialContext.init(Unknown Source)
    at javax.naming.InitialContext.<init>(Unknown Source)
    at javax.naming.directory.InitialDirContext.<init>(Unknown Source)
    at com.mycompany.fde.util.LDAPHelper.initialBindSSL(LDAPHelper.java:116)
    at com.mycompany.fde.util.LDAPHelper.<init>(LDAPHelper.java:91)
    at com.mycompany.fde.util.LDAPHelper.getInstance(LDAPHelper.java:58)
    at com.mycompany.fde.server.work.StartupWork.startupStage1(StartupWork.java:224)
    at com.mycompany.fde.server.work.StartupWork.call(StartupWork.java:121)
    at com.mycompany.fde.server.work.StartupWork.call(StartupWork.java:47)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext)
    at javax.net.ssl.DefaultSSLSocketFactory.throwException(Unknown Source)
    at javax.net.ssl.DefaultSSLSocketFactory.createSocket(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at com.sun.jndi.ldap.Connection.createSocket(Unknown Source)
    ... 24 more
Caused by: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext)
    at java.security.Provider$Service.newInstance(Unknown Source)
    at sun.security.jca.GetInstance.getInstance(Unknown Source)
    at sun.security.jca.GetInstance.getInstance(Unknown Source)
    at javax.net.ssl.SSLContext.getInstance(Unknown Source)
    at javax.net.ssl.SSLContext.getDefault(Unknown Source)
    at javax.net.ssl.SSLSocketFactory.getDefault(Unknown Source)
    ... 29 more
Caused by: java.io.IOException: Keystore was tampered with, or password was incorrect
    at sun.security.provider.JavaKeyStore.engineLoad(Unknown Source)
    at sun.security.provider.JavaKeyStore$JKS.engineLoad(Unknown Source)
    at java.security.KeyStore.load(Unknown Source)
    at sun.security.ssl.TrustManagerFactoryImpl.getCacertsKeyStore(Unknown Source)
    at sun.security.ssl.SSLContextImpl$DefaultSSLContext.getDefaultTrustManager(Unknown Source)
    at sun.security.ssl.SSLContextImpl$DefaultSSLContext.<init>(Unknown Source)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    ... 35 more
Caused by: java.security.UnrecoverableKeyException: Password verification failed
    ... 45 more

我完全不知所措 - 任何帮助/想法将不胜感激!

【问题讨论】:

  • 从堆栈跟踪来看,TrustManagerFactoryImpl.getCacertsKeyStore() 期间似乎发生了一些事情。如果你在服务器上查看%JAVA_HOME%\jre\lib\security,你能看到那里有一个名为cacerts 的文件吗?
  • 如果有cacerts 文件,可能它的密码不是默认密码,即“changeit”。
  • 是的,我试过让它使用cacerts(即使是在全新的Java安装之后)或jssecacerts,但它总是失败并出现同样的错误。这就是为什么我尝试使用自定义存储(与加载正常的密钥库相同)。
  • 那么当您完全省略 -Djavax.net.ssl.trustStorePassword-Djavax.net.ssl.trustStore 参数时会发生什么?如果您需要 LDAP 的自定义证书,您还可以将证书导入 JVM 的默认信任库 (cacerts)。
  • 不幸的是,同样的错误 - 调试表明它采用默认的cacerts(或jssecacerts,如果我放一个)但失败

标签: java tomcat ssl


【解决方案1】:

感谢大家的帮助,我终于发现不知什么原因,确实有人在Catalina.properties(通过javax.net.ssl.trustStorePassword)设置了信任库密码。似乎这甚至优先于 Tomcat UI 中设置的 java 变量:(

【讨论】:

    【解决方案2】:

    为了完整起见,如果相同配置的密钥库文件不存在,也会发生这种情况(此处:错误的 file:/// 前缀)。它仍然导致:

    trustStore is: No File Available, using empty keystore.
    trustStore type is : jks
    trustStore provider is : 
    init truststore
    keyStore is : file:///c:/my.jks
    keyStore type is : jks
    keyStore provider is : 
    

    与 OpenJDK 1.8.0.181 相比,keyStore is : 行只会误导性地输出 javax.net.ssl.keyStore [1],而给定的 trustStore 会首先检查是否存在 [2]。

    [1] sun.security.ssl.SSLContextImpl
    [2] sun.security.ssl.TrustManagerFactoryImpl

    【讨论】:

      【解决方案3】:

      您无需提供信任库密码。所以,不要。

      NB keytool -list 根本不需要密码,也不能证明你知道正确的密码。另一方面,您遇到的错误密码不正确的证明。

      您不应该对密钥库和信任库使用相同的文件。

      【讨论】:

      • 当你的代码调用KeyStore.load你可以省略密码,但是当SSLContext创建默认上下文时它不会;您唯一的选择是指定 pw 或使用默认值。使用同一个文件通常是个坏主意,但这里似乎只是为了调试。
      • @dave_thompson_085 我有数英亩的工作代码证明并非如此。如果SSLContext 在任何地方使用默认密码,我还没有看到它记录在案,或者遇到了在 20 年的 JSSE 编程中可以解释的情况。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-02
      • 2018-08-24
      • 1970-01-01
      • 2016-07-28
      • 2016-09-16
      • 2016-10-26
      • 2016-08-02
      相关资源
      最近更新 更多