Author: markt
Date: Wed Dec 13 10:42:15 2017
New Revision: 1817997
URL: http://svn.apache.org/viewvc?rev=1817997&view=rev
Log:
Partial fix for https://bz.apache.org/bugzilla/show_bug.cgi?id=61566
Certificate chains are now exposed for virtual hosts configured using a Java
key store.
Added:
tomcat/trunk/webapps/manager/WEB-INF/jsp/connectorCerts.jsp (with props)
Modified:
tomcat/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java
tomcat/trunk/java/org/apache/catalina/manager/LocalStrings.properties
tomcat/trunk/java/org/apache/catalina/manager/ManagerServlet.java
tomcat/trunk/java/org/apache/tomcat/util/net/SSLContext.java
tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESSLContext.java
tomcat/trunk/java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java
tomcat/trunk/webapps/docs/changelog.xml
tomcat/trunk/webapps/manager/WEB-INF/jsp/connectorCiphers.jsp
Modified: tomcat/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java?rev=1817997&r1=1817996&r2=1817997&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java
(original)
+++ tomcat/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java Wed
Dec 13 10:42:15 2017
@@ -85,6 +85,7 @@ public final class HTMLManagerServlet ex
static final String sessionsListJspPath = "/WEB-INF/jsp/sessionsList.jsp";
static final String sessionDetailJspPath =
"/WEB-INF/jsp/sessionDetail.jsp";
static final String connectorCiphersJspPath =
"/WEB-INF/jsp/connectorCiphers.jsp";
+ static final String connectorCertsJspPath =
"/WEB-INF/jsp/connectorCerts.jsp";
private boolean showProxySessions = false;
@@ -138,6 +139,8 @@ public final class HTMLManagerServlet ex
}
} else if (command.equals("/sslConnectorCiphers")) {
sslConnectorCiphers(request, response);
+ } else if (command.equals("/sslConnectorCerts")) {
+ sslConnectorHostCerts(request, response);
} else if (command.equals("/upload") || command.equals("/deploy") ||
command.equals("/reload") || command.equals("/undeploy") ||
command.equals("/expire") || command.equals("/start") ||
@@ -535,7 +538,7 @@ public final class HTMLManagerServlet ex
writer.print(MessageFormat.format(UPLOAD_SECTION, args));
// Diagnostics section
- args = new Object[9];
+ args = new Object[12];
args[0] = smClient.getString("htmlManagerServlet.diagnosticsTitle");
args[1] = smClient.getString("htmlManagerServlet.diagnosticsLeak");
args[2] = response.encodeURL(
@@ -547,6 +550,10 @@ public final class HTMLManagerServlet ex
request.getContextPath() + "/html/sslConnectorCiphers");
args[7] =
smClient.getString("htmlManagerServlet.diagnosticsSslConnectorCipherButton");
args[8] =
smClient.getString("htmlManagerServlet.diagnosticsSslConnectorCipherText");
+ args[9] = response.encodeURL(
+ request.getContextPath() + "/html/sslConnectorCerts");
+ args[10] =
smClient.getString("htmlManagerServlet.diagnosticsSslConnectorCertsButton");
+ args[11] =
smClient.getString("htmlManagerServlet.diagnosticsSslConnectorCertsText");
writer.print(MessageFormat.format(DIAGNOSTICS_SECTION, args));
// Server Header Section
@@ -727,6 +734,15 @@ public final class HTMLManagerServlet ex
connectorCiphersJspPath).forward(request, response);
}
+
+ protected void sslConnectorHostCerts(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException
{
+ request.setAttribute("certList", getConnectorCerts());
+ getServletContext().getRequestDispatcher(
+ connectorCertsJspPath).forward(request, response);
+ }
+
+
/**
* @see javax.servlet.Servlet#getServletInfo()
*/
@@ -1292,6 +1308,7 @@ public final class HTMLManagerServlet ex
"<tr>\n" +
" <td colspan=\"2\" class=\"title\">{0}</td>\n" +
"</tr>\n" +
+
"<tr>\n" +
" <td colspan=\"2\" class=\"header-left\"><small>{1}</small></td>\n" +
"</tr>\n" +
@@ -1311,6 +1328,7 @@ public final class HTMLManagerServlet ex
"</form>\n" +
"</td>\n" +
"</tr>\n" +
+
"<tr>\n" +
" <td colspan=\"2\" class=\"header-left\"><small>{5}</small></td>\n" +
"</tr>\n" +
@@ -1330,6 +1348,28 @@ public final class HTMLManagerServlet ex
"</form>\n" +
"</td>\n" +
"</tr>\n" +
+
+ "<tr>\n" +
+ " <td colspan=\"2\">\n" +
+ "<form method=\"post\" action=\"{9}\">\n" +
+ "<table cellspacing=\"0\" cellpadding=\"3\">\n" +
+ "<tr>\n" +
+ " <td class=\"row-left\">\n" +
+ " <input type=\"submit\" value=\"{10}\">\n" +
+ " </td>\n" +
+ " <td class=\"row-left\">\n" +
+ " <small>{11}</small>\n" +
+ " </td>\n" +
+ "</tr>\n" +
+ "</table>\n" +
+ "</form>\n" +
+ "</td>\n" +
+ "</tr>\n" +
+ "</table>\n" +
+ "</form>\n" +
+
+ "</td>\n" +
+ "</tr>\n" +
"</table>\n" +
"<br>";
}
Modified: tomcat/trunk/java/org/apache/catalina/manager/LocalStrings.properties
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/manager/LocalStrings.properties?rev=1817997&r1=1817996&r2=1817997&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/manager/LocalStrings.properties
(original)
+++ tomcat/trunk/java/org/apache/catalina/manager/LocalStrings.properties Wed
Dec 13 10:42:15 2017
@@ -48,9 +48,11 @@ htmlManagerServlet.deployWar=WAR or Dire
htmlManagerServlet.diagnosticsLeak=Check to see if a web application has
caused a memory leak on stop, reload or undeploy
htmlManagerServlet.diagnosticsLeakButton=Find leaks
htmlManagerServlet.diagnosticsLeakWarning=This diagnostic check will trigger a
full garbage collection. Use it with extreme caution on production systems.
-htmlManagerServlet.diagnosticsSsl=SSL connector configuration diagnostics
-htmlManagerServlet.diagnosticsSslConnectorCipherButton=Connector ciphers
-htmlManagerServlet.diagnosticsSslConnectorCipherText=List the configured
ciphers for each connector
+htmlManagerServlet.diagnosticsSsl=TLS connector configuration diagnostics
+htmlManagerServlet.diagnosticsSslConnectorCipherButton=Ciphers
+htmlManagerServlet.diagnosticsSslConnectorCipherText=List the configured TLS
virtual hosts and the ciphers for each
+htmlManagerServlet.diagnosticsSslConnectorCertsButton=Certificates
+htmlManagerServlet.diagnosticsSslConnectorCertsText=List the configured TLS
virtual hosts and the certificate chain for each
htmlManagerServlet.diagnosticsTitle=Diagnostics
htmlManagerServlet.findleaksList=\
The following web applications were stopped (reloaded, undeployed), but
their\n\
@@ -72,6 +74,7 @@ htmlManagerServlet.serverTitle=Server In
htmlManagerServlet.serverVersion=Tomcat Version
htmlManagerServlet.title=Tomcat Web Application Manager
managerServlet.alreadyContext=FAIL - Application already exists at path [{0}]
+managerServlet.certsNotAvailable=Certificate information cannot be obtained
from this connector at runtime
managerServlet.deleteFail=FAIL - Unable to delete [{0}]. The continued
presence of this file may cause problems.
managerServlet.deployed=OK - Deployed application at context path [{0}]
managerServlet.deployFailed=FAIL - Failed to deploy application at context
path [{0}]
Modified: tomcat/trunk/java/org/apache/catalina/manager/ManagerServlet.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/manager/ManagerServlet.java?rev=1817997&r1=1817996&r2=1817997&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/manager/ManagerServlet.java (original)
+++ tomcat/trunk/java/org/apache/catalina/manager/ManagerServlet.java Wed Dec
13 10:42:15 2017
@@ -22,6 +22,8 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
@@ -30,6 +32,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Set;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
@@ -62,7 +65,9 @@ import org.apache.catalina.util.ServerIn
import org.apache.tomcat.util.Diagnostics;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.modeler.Registry;
+import org.apache.tomcat.util.net.SSLContext;
import org.apache.tomcat.util.net.SSLHostConfig;
+import org.apache.tomcat.util.net.SSLHostConfigCertificate;
import org.apache.tomcat.util.res.StringManager;
import org.apache.tomcat.util.security.Escape;
@@ -1712,4 +1717,48 @@ public class ManagerServlet extends Http
}
return result;
}
+
+
+ protected Map<String,List<String>> getConnectorCerts() {
+ Map<String,List<String>> result = new HashMap<>();
+
+ Engine e = (Engine) host.getParent();
+ Service s = e.getService();
+ Connector connectors[] = s.findConnectors();
+ for (Connector connector : connectors) {
+ if (Boolean.TRUE.equals(connector.getProperty("SSLEnabled"))) {
+ SSLHostConfig[] sslHostConfigs =
connector.getProtocolHandler().findSslHostConfigs();
+ for (SSLHostConfig sslHostConfig : sslHostConfigs) {
+ Set<SSLHostConfigCertificate> sslHostConfigCerts =
+ sslHostConfig.getCertificates();
+ for (SSLHostConfigCertificate sslHostConfigCert :
sslHostConfigCerts) {
+ String name = connector.toString() + "-" +
sslHostConfig.getHostName() +
+ "-" + sslHostConfigCert.getType();
+ List<String> certList = new ArrayList<>();
+ SSLContext sslContext =
sslHostConfigCert.getSslContext();
+ String alias =
sslHostConfigCert.getCertificateKeyAlias();
+ if (alias == null) {
+ alias = "tomcat";
+ }
+ X509Certificate[] certs =
sslContext.getCertificateChain(alias);
+ if (certs == null) {
+
certList.add(sm.getString("managerServlet.certsNotAvailable"));
+ } else {
+ for (Certificate cert : certs) {
+ certList.add(cert.toString());
+ }
+ }
+ result.put(name, certList);
+ }
+ }
+ } else {
+ List<String> certList = new ArrayList<>(1);
+ certList.add(sm.getString("managerServlet.notSslConnector"));
+ result.put(connector.toString(), certList);
+ }
+ }
+
+ return result;
+ }
+
}
Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SSLContext.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SSLContext.java?rev=1817997&r1=1817996&r2=1817997&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SSLContext.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SSLContext.java Wed Dec 13
10:42:15 2017
@@ -19,6 +19,7 @@ package org.apache.tomcat.util.net;
import java.security.KeyManagementException;
import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLEngine;
@@ -47,4 +48,5 @@ public interface SSLContext {
public SSLParameters getSupportedSSLParameters();
+ public X509Certificate[] getCertificateChain(String alias);
}
Modified: tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESSLContext.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESSLContext.java?rev=1817997&r1=1817996&r2=1817997&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESSLContext.java
(original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESSLContext.java Wed
Dec 13 10:42:15 2017
@@ -20,6 +20,7 @@ package org.apache.tomcat.util.net.jsse;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLEngine;
@@ -27,12 +28,15 @@ import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509KeyManager;
import org.apache.tomcat.util.net.SSLContext;
class JSSESSLContext implements SSLContext {
private javax.net.ssl.SSLContext context;
+ private KeyManager[] kms;
+
JSSESSLContext(String protocol) throws NoSuchAlgorithmException {
context = javax.net.ssl.SSLContext.getInstance(protocol);
}
@@ -40,6 +44,7 @@ class JSSESSLContext implements SSLConte
@Override
public void init(KeyManager[] kms, TrustManager[] tms, SecureRandom sr)
throws KeyManagementException {
+ this.kms = kms;
context.init(kms, tms, sr);
}
@@ -67,4 +72,16 @@ class JSSESSLContext implements SSLConte
return context.getSupportedSSLParameters();
}
+ @Override
+ public X509Certificate[] getCertificateChain(String alias) {
+ X509Certificate[] result = null;
+ if (kms != null) {
+ for (int i = 0; i < kms.length && result == null; i++) {
+ if (kms[i] instanceof X509KeyManager) {
+ result = ((X509KeyManager)
kms[i]).getCertificateChain(alias);
+ }
+ }
+ }
+ return result;
+ }
}
Modified:
tomcat/trunk/java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java?rev=1817997&r1=1817996&r2=1817997&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java
(original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java
Wed Dec 13 10:42:15 2017
@@ -68,6 +68,7 @@ public class OpenSSLContext implements o
private final SSLHostConfig sslHostConfig;
private final SSLHostConfigCertificate certificate;
private OpenSSLSessionContext sessionContext;
+ private X509KeyManager x509KeyManager;
private final List<String> negotiableProtocols;
@@ -286,17 +287,17 @@ public class OpenSSLContext implements o
SSLHostConfig.adjustRelativePath(
sslHostConfig.getCertificateRevocationListPath()));
} else {
- X509KeyManager keyManager = chooseKeyManager(kms);
+ x509KeyManager = chooseKeyManager(kms);
String alias = certificate.getCertificateKeyAlias();
if (alias == null) {
alias = "tomcat";
}
- X509Certificate[] chain =
keyManager.getCertificateChain(alias);
+ X509Certificate[] chain =
x509KeyManager.getCertificateChain(alias);
if (chain == null) {
- alias = findAlias(keyManager, certificate);
- chain = keyManager.getCertificateChain(alias);
+ alias = findAlias(x509KeyManager, certificate);
+ chain = x509KeyManager.getCertificateChain(alias);
}
- PrivateKey key = keyManager.getPrivateKey(alias);
+ PrivateKey key = x509KeyManager.getPrivateKey(alias);
StringBuilder sb = new StringBuilder(BEGIN_KEY);
sb.append(Base64.getMimeEncoder(64, new byte[]
{'\n'}).encodeToString(key.getEncoded()));
sb.append(END_KEY);
@@ -514,6 +515,20 @@ public class OpenSSLContext implements o
}
@Override
+ public X509Certificate[] getCertificateChain(String alias) {
+ if (alias == null) {
+ alias = "tomcat";
+ }
+ X509Certificate[] chain = x509KeyManager.getCertificateChain(alias);
+ if (chain == null) {
+ alias = findAlias(x509KeyManager, certificate);
+ chain = x509KeyManager.getCertificateChain(alias);
+ }
+
+ return chain;
+ }
+
+ @Override
protected void finalize() throws Throwable {
/*
* When an SSLHostConfig is replaced at runtime, it is not possible to
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1817997&r1=1817996&r2=1817997&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Wed Dec 13 10:42:15 2017
@@ -90,6 +90,12 @@
MBean documentation so users have a reference to use when constructing
mbeans-descriptiors.xml files for custom components. (markt)
</add>
+ <add>
+ <bug>61566</bug>: Provide a partial fix for this issue. The fix exposes
+ the currently in use certificate chain for all virtual hosts configured
+ using the JSSE style (keystore) TLS configuration via the Manager web
+ application.
+ </add>
</changelog>
</subsection>
<subsection name="Other">
Added: tomcat/trunk/webapps/manager/WEB-INF/jsp/connectorCerts.jsp
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/manager/WEB-INF/jsp/connectorCerts.jsp?rev=1817997&view=auto
==============================================================================
--- tomcat/trunk/webapps/manager/WEB-INF/jsp/connectorCerts.jsp (added)
+++ tomcat/trunk/webapps/manager/WEB-INF/jsp/connectorCerts.jsp Wed Dec 13
10:42:15 2017
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<%--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+--%>
+<%@page session="false" contentType="text/html; charset=ISO-8859-1" %>
+<%@page import="java.util.Map" %>
+<%@page import="java.util.Map.Entry" %>
+<%@page import="java.util.List" %>
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<% Map<String,List<String>> certList = (Map<String,List<String>>)
request.getAttribute("certList");
+%>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1"/>
+ <meta http-equiv="pragma" content="no-cache"/><!-- HTTP 1.0 -->
+ <meta http-equiv="cache-control" content="no-cache,must-revalidate"/><!--
HTTP 1.1 -->
+ <meta http-equiv="expires" content="0"/><!-- 0 is an invalid value and
should be treated as 'now' -->
+ <meta http-equiv="content-language" content="en"/>
+ <meta name="copyright" content="copyright 2005-2017 the Apache Software
Foundation"/>
+ <meta name="robots" content="noindex,nofollow,noarchive"/>
+ <title>Configured certificate chains per Connector</title>
+</head>
+<body>
+<h1>Configured ciphers per Connector</h1>
+
+<table border="1" cellpadding="2" cellspacing="2" width="100%">
+ <thead>
+ <tr>
+ <th>Connector / TLS Virtual Host / Certificate type</th>
+ <th>Certificate chain</th>
+ </tr>
+ </thead>
+ <tbody>
+ <%
+ for (Map.Entry<String, List<String>> entry : certList.entrySet()) {
+ %>
+ <tr>
+ <td><%=entry.getKey()%></td>
+ <td>
+ <%
+ for (String cert : entry.getValue()) {
+ %>
+ <pre><%=cert%></pre>
+ <%
+ }
+ %>
+ </td>
+ </tr>
+ <%
+ }
+ %>
+ </tbody>
+</table>
+
+<form method="get" action="<%=request.getContextPath()%>/html">
+ <p style="text-align: center;">
+ <input type="submit" value="Return to main page" />
+ </p>
+</form>
+
+<%--div style="display: none;">
+<p>
+ <a href="http://validator.w3.org/check?uri=referer"><img
+ src="http://www.w3.org/Icons/valid-html401"
+ alt="Valid HTML 4.01!" height="31" width="88"></a>
+ <a href="http://validator.w3.org/check?uri=referer"><img
+ src="http://www.w3.org/Icons/valid-xhtml10"
+ alt="Valid XHTML 1.0!" height="31" width="88" /></a>
+ <a href="http://validator.w3.org/check?uri=referer"><img
+ src="http://www.w3.org/Icons/valid-xhtml11"
+ alt="Valid XHTML 1.1!" height="31" width="88" /></a>
+</p>
+</div--%>
+
+</body>
+</html>
Propchange: tomcat/trunk/webapps/manager/WEB-INF/jsp/connectorCerts.jsp
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tomcat/trunk/webapps/manager/WEB-INF/jsp/connectorCiphers.jsp
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/manager/WEB-INF/jsp/connectorCiphers.jsp?rev=1817997&r1=1817996&r2=1817997&view=diff
==============================================================================
--- tomcat/trunk/webapps/manager/WEB-INF/jsp/connectorCiphers.jsp (original)
+++ tomcat/trunk/webapps/manager/WEB-INF/jsp/connectorCiphers.jsp Wed Dec 13
10:42:15 2017
@@ -42,7 +42,7 @@
<table border="1" cellpadding="2" cellspacing="2" width="100%">
<thead>
<tr>
- <th>Connector</th>
+ <th>Connector / TLS Virtual Host</th>
<th>Enabled Ciphers</th>
</tr>
</thead>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]