查找或初始化解决“证书中的主机名不匹配”所需的密钥库 [英] Find or initialize the keystore needed to solve "hostname in certificate didn't match"

查看:2510
本文介绍了查找或初始化解决“证书中的主机名不匹配”所需的密钥库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近继承了一个实验室Ubuntu LAMP服务器,该服务器相对被忽视并且仍在运行Struts 1.0应用程序。我们正在尝试进行彻底的改造,但同时在日志中抛出的唯一错误是 javax.net.ssl.SSLException:证书中的主机名不匹配错误。我们希望在我们写下替换件时暂时修补它。我已经阅读了几个关于母校的SO问题(例如 1 2 3 4 )它好像是 Sargent的解决方案是最佳选择。



不幸的是,我进入服务器时完全没有文档或从设置它的组中返回电子邮件(幸运的是,每个策略都没有对Java进行模糊处理)。我查找了任何密钥库文件(在文件名中搜索keystore或 .jks 文件),但我没有找到任何文件。这导致我认为我需要制作一个新的并且在之前初始化它 webClient.getPage 。到目前为止,我已经能够将 .jks 文件设置得很好,只是它不会更改主机名匹配错误。



有没有办法查看servlet使用的密钥库是什么,它的位置恰好是什么?或者,制作一个新的并使用/初始化的正确方法是什么?






其他详细信息



有一些事情对我来说很奇怪。主要的是我不明白为什么主机名不正确。被提取的网站是 https://www.ncbi.nlm.nih.gov/account/ ,如果您在浏览器中导航到它,肯定会提取正确的证书。我想知道是不是因为 WebClient(BrowserVersion.FIREFOX_17)设置为古老的 FIREFOX_17 。我应该把它从17改为31吗?有很多东西可以升级,但是当我们要从头开始创建文档时,我希望尽可能少地在旧实例上进行更改,以期让它继续运行几个月。安装在服务器上的FIREFOX版本并不接近当前的以太(不是它已经使用过),但我想改变 BrowserVersion 只是改变了回复的格式。



这是代码,以抛出错误的行结束:

  private Vector updateRDLpubs(Vector orderList,DataSource dataSource)
throws Exception
{
Vector removeList = new Vector();
Vector historyList = new Vector();
try
{
SimpleDateFormat format = new SimpleDateFormat(MM / dd / yyyy);
Calendar cal = Calendar.getInstance();
cal.add(5,-5);
Date days5Back = cal.getTime();

WebClient webClient = new WebClient(BrowserVersion.FIREFOX_17);
webClient.setThrowExceptionOnFailingStatusCode(false);
HtmlPage page =(HtmlPage)webClient.getPage(https://www.ncbi.nlm.nih.gov/account/);

这是错误的堆栈跟踪:

  at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:227)
at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier .verify(BrowserCompatHostnameVerifier.java:54)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:147)
at org.apache.http.conn.ssl.AbstractVerifier .verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572)
at com.gargoylesoftware.htmlunit.HtmlUnitSSLSocketFactory.connectSocket(HtmlUnitSSLSocketFactory) .java:171)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl .java:294)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:645)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:480)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at com.gargoylesoftware.htmlunit.HttpWebConnection.getResponse(HttpWebConnection.java:172)
at com.gargoylesoftware.htmlunit.WebClient.loadWebResponseFromWebConnection(WebClient.java:1486)
at com.gargoylesoftware.htmlunit.WebClient。 loadWebResponse(WebClient.java:1403)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:305)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:374)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:359)
at tanklab.UpdateRDLJob2.updateRDLpubs(UpdateRDLJob2.java:241)
at tanklab.UpdateRDLJob2.execute(UpdateRDLJob2) .java:79)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
at org.quartz.simpl.SimpleThreadPool $ WorkerThread.run(SimpleThreadPool.java:525)


解决方案

编辑:啊,你正在使用HTMLUnit。您的问题可能是您的HTMLUnit严重过时 - 使用 https://tersesystems.com/2014/03/31/testing-hostname-verification/ 然后将HTMLUnit升级到最新版本(如果没有显示)。



更多编辑:为什么要从Quartz使用HTMLUnit?他们是否尝试将其用作通用HTTP客户端?它不是为此设计的。



最好的参考是Bulletproof TLS,它有一章关于JSSE和Tomcat。


有没有办法看看servlet使用了什么密钥库,以及它的位置是什么?




这取决于正在设置的SSLEngine - 如果你在servlet中运行,很可能应用服务器已经设置了你的SSL配置。但是,您可以通过打开 -Djavax.net.debug = ALL 来调试JVM,但它不会告诉您证书来自文件系统的哪个位置,除非您编码自定义KeyStore和TrustManager(这是蹩脚的)。以下是调试信息:






或者,制作一个新的并使用/初始化它的正确方法是什么?


这取决于您的应用程序服务器。如果您只需要提供自定义SSLEngine,您可以执行以下操作(来自 https://github.com/wsargent/activator-play-tls-example/blob/master/app/https/CustomSSLEngineProvider.scala ):

  class CustomSSLEngineProvider(appProvider:ApplicationProvider)扩展SSLEngineProvider {

def readPassword():Array [Char] = {
val passwordPath = FileSystems.getDefault.getPath(certs,password)
Files.readAllLines(passwordPath).get(0).toCharArray
}

def readKeyInputStream ():java.io.InputStream = {
val keyPath = FileSystems.getDefault.getPath(certs,example.com.jks)
Files.newInputStream(keyPath)
}

def readTrustInputStream():java.io.InputStream = {
val keyPath = FileSystems.getDefault.getPath(certs,clientca.jks)
Files。 newInputStream(keyPath)
}

def readKeyManagers():Array [KeyManager] = {
val password = readPassword()
val keyInputStream = readKeyInputStream()
try {
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType)
keyStore.load(keyInputStream,password)
val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm)
kmf.init(keyStore,密码)
kmf.getKeyManagers
} finally {
keyInputStream.close()
}
}

def readTrustManagers():Array [TrustManager] = {
val password = readPassword()
val trustInputStream = readTrustInputStream()
try {
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType )
keyStore.load(trustInputStream,password)
val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
tmf.init(keyStore)
tmf.getTrustMan agers
} finally {
trustInputStream.close()
}
}

def createSSLContext(applicationProvider:ApplicationProvider):SSLContext = {
val keyManagers = readKeyManagers()
val trustManagers = readTrustManagers()

//配置SSL上下文以使用TLS
val sslContext = SSLContext.getInstance(TLS)
sslContext.init(keyManagers,trustManagers,null)
sslContext
}

覆盖def createSSLEngine():SSLEngine = {
val sslContext = createSSLContext(appProvider)

//从克隆的默认SSL参数开始...
val sslParameters = sslContext.getDefaultSSLParameters

//告诉服务器忽略客户端的密码套房偏好。
// http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#cipher_suite_preference
sslParameters.setUseCipherSuitesOrder(true)

// http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#SSLParameters
val needClientAuth = java.lang.System.getProperty( play.ssl.needClientAuth)
sslParameters.setNeedClientAuth(java.lang.Boolean.parseBoolean(needClientAuth))

//克隆并修改默认的SSL参数。
val engine = sslContext.createSSLEngine
engine.setSSLParameters(sslParameters)

engine
}

}


I recently inherited a lab Ubuntu LAMP server that has been relatively neglected and still running a Struts 1.0 application. We are preping for a complete overhaul, but in the mean time the only error that is being thrown in the logs is a javax.net.ssl.SSLException: hostname in certificate didn't match error. It's our hope to patch this temporarily while we write the replacement. I've read several SO questions on the mater (eg 1, 2, 3, 4) and it seemed like Will Sargent's solution was the best choice.

Unfortunately I'm going into the server with utterly no documentation or returned email from the group that set it up (luckily none of the Java was obfuscated per policy). I looked for any keystore files (searching for "keystore" in the file name or .jks files), but I didn't find any. Which lead me think that I needed to make a new one and initialize it prior to calling the webClient.getPage. So far I have been able to make the .jks file just fine, it's just it doesn't change the hostname match error.

Is there a way to see what keystore if any is being used by a servlet, and what its location happens to be? Alternatively, what is the proper way to make a new one and have it be used/initialized?


Additional Details

There are a few things about this that are odd to me. The main one is I don't understand why the hostname wouldn't be correct. The site being pulled is https://www.ncbi.nlm.nih.gov/account/ which if you navigate to it in a browser certainly pulls the correct certificate. I'm wondering if it's because the WebClient(BrowserVersion.FIREFOX_17) is set to the archaic FIREFOX_17. Should I just change that from 17 to 31? There are plenty of things that could be upgraded, but as we're going to start from scratch to have documentation, I want to change as little as possible on the old instance to hopefully keep it running for a few more months. The FIREFOX version installed on the server isn't close to current ether (not that it's used), but I was thinking changing the BrowserVersion just changed how the reply was formatted.

Here is the code, ending on the line throwing the error:

  private Vector updateRDLpubs(Vector orderList, DataSource dataSource)
    throws Exception
  {
    Vector removeList = new Vector();
    Vector historyList = new Vector();
    try
    {
      SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");
      Calendar cal = Calendar.getInstance();
      cal.add(5, -5);
      Date days5Back = cal.getTime();

      WebClient webClient = new WebClient(BrowserVersion.FIREFOX_17);
      webClient.setThrowExceptionOnFailingStatusCode(false);
      HtmlPage page = (HtmlPage)webClient.getPage("https://www.ncbi.nlm.nih.gov/account/");

And here is the stack trace on the error:

at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:227)
at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java:54)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:147)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572)
at com.gargoylesoftware.htmlunit.HtmlUnitSSLSocketFactory.connectSocket(HtmlUnitSSLSocketFactory.java:171)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:645)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:480)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at com.gargoylesoftware.htmlunit.HttpWebConnection.getResponse(HttpWebConnection.java:172)
at com.gargoylesoftware.htmlunit.WebClient.loadWebResponseFromWebConnection(WebClient.java:1486)
at com.gargoylesoftware.htmlunit.WebClient.loadWebResponse(WebClient.java:1403)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:305)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:374)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:359)
at tanklab.UpdateRDLJob2.updateRDLpubs(UpdateRDLJob2.java:241)
at tanklab.UpdateRDLJob2.execute(UpdateRDLJob2.java:79)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:525)

解决方案

EDIT: Ahh, you are using HTMLUnit. Your problem is probably that your HTMLUnit is severely out of date -- check against the server using https://tersesystems.com/2014/03/31/testing-hostname-verification/ and then upgrade HTMLUnit to the latest if nothing shows up.

MORE EDIT: Why is HTMLUnit being used from Quartz? Are they trying to use it as a general HTTP Client? It's not designed for that.

The best reference on this is going to be Bulletproof TLS, which has a chapter about JSSE and Tomcat.

Is there a way to see what keystore if any is being used by a servlet, and what its location happens to be?

This depends on an SSLEngine being set up -- if you're running inside a servlet, most likely the app server has already set up your SSL configuration already. However, you can debug your JVM by turning on -Djavax.net.debug=ALL, but it doesn't tell you what location on the filesystem the certificate came from unless you coded a custom KeyStore and TrustManager (which is lame). Here's the debug info though:

Alternatively, what is the proper way to make a new one and have it be used/initialized?

This depends on your application server. If you just need to provide a custom SSLEngine, you can do something like this (from https://github.com/wsargent/activator-play-tls-example/blob/master/app/https/CustomSSLEngineProvider.scala):

class CustomSSLEngineProvider(appProvider: ApplicationProvider) extends SSLEngineProvider {

  def readPassword(): Array[Char] = {
    val passwordPath = FileSystems.getDefault.getPath("certs", "password")
    Files.readAllLines(passwordPath).get(0).toCharArray
  }

  def readKeyInputStream(): java.io.InputStream = {
    val keyPath = FileSystems.getDefault.getPath("certs", "example.com.jks")
    Files.newInputStream(keyPath)
  }

  def readTrustInputStream(): java.io.InputStream = {
    val keyPath = FileSystems.getDefault.getPath("certs", "clientca.jks")
    Files.newInputStream(keyPath)
  }

  def readKeyManagers(): Array[KeyManager] = {
    val password = readPassword()
    val keyInputStream = readKeyInputStream()
    try {
      val keyStore = KeyStore.getInstance(KeyStore.getDefaultType)
      keyStore.load(keyInputStream, password)
      val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm)
      kmf.init(keyStore, password)
      kmf.getKeyManagers
    } finally {
      keyInputStream.close()
    }
  }

  def readTrustManagers(): Array[TrustManager] = {
    val password = readPassword()
    val trustInputStream = readTrustInputStream()
    try {
      val keyStore = KeyStore.getInstance(KeyStore.getDefaultType)
      keyStore.load(trustInputStream, password)
      val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
      tmf.init(keyStore)
      tmf.getTrustManagers
    } finally {
      trustInputStream.close()
    }
  }

  def createSSLContext(applicationProvider: ApplicationProvider): SSLContext = {
    val keyManagers = readKeyManagers()
    val trustManagers = readTrustManagers()

    // Configure the SSL context to use TLS
    val sslContext = SSLContext.getInstance("TLS")
    sslContext.init(keyManagers, trustManagers, null)
    sslContext
  }

  override def createSSLEngine(): SSLEngine = {
    val sslContext = createSSLContext(appProvider)

    // Start off with a clone of the default SSL parameters...
    val sslParameters = sslContext.getDefaultSSLParameters

    // Tells the server to ignore client's cipher suite preference.
    // http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#cipher_suite_preference
    sslParameters.setUseCipherSuitesOrder(true)

    // http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#SSLParameters
    val needClientAuth = java.lang.System.getProperty("play.ssl.needClientAuth")
    sslParameters.setNeedClientAuth(java.lang.Boolean.parseBoolean(needClientAuth))

    // Clone and modify the default SSL parameters.
    val engine = sslContext.createSSLEngine
    engine.setSSLParameters(sslParameters)

    engine
  }

}

这篇关于查找或初始化解决“证书中的主机名不匹配”所需的密钥库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆