This commit is contained in:
2024-11-30 19:03:49 +08:00
commit 1e6763c160
3806 changed files with 737676 additions and 0 deletions

View File

@@ -0,0 +1,141 @@
/*
* 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.
*/
package org.apache.tomcat.util.net;
import org.junit.Assert;
import org.junit.Test;
/**
* Mostly examples from RFC 5952
*/
public class IPv6UtilsTest {
@Test
public void testMayBeIPv6Address() {
Assert.assertFalse(IPv6Utils.mayBeIPv6Address(null));
Assert.assertTrue(IPv6Utils.mayBeIPv6Address("::1"));
Assert.assertTrue(IPv6Utils.mayBeIPv6Address("::"));
Assert.assertTrue(IPv6Utils.mayBeIPv6Address("2001:db8:0:0:1:0:0:1"));
Assert.assertFalse(IPv6Utils.mayBeIPv6Address(""));
Assert.assertFalse(IPv6Utils.mayBeIPv6Address(":1"));
Assert.assertFalse(IPv6Utils.mayBeIPv6Address("123.123.123.123"));
Assert.assertFalse(IPv6Utils.mayBeIPv6Address("tomcat.eu.apache.org:443"));
}
@Test
public void testCanonize() {
Assert.assertNull(IPv6Utils.canonize(null));
Assert.assertEquals("", IPv6Utils.canonize(""));
// IPv4-safe
Assert.assertEquals("123.123.123.123", IPv6Utils.canonize("123.123.123.123"));
Assert.assertEquals("123.1.2.23", IPv6Utils.canonize("123.1.2.23"));
// Introductory RFC 5952 examples
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:db8:0:0:1:0:0:1"));
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:0db8:0:0:1:0:0:1"));
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:db8::1:0:0:1"));
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:db8::0:1:0:0:1"));
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:0db8::1:0:0:1"));
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:db8:0:0:1::1"));
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:db8:0000:0:1::1"));
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:DB8:0:0:1::1"));
// Strip leading zeros (2.1)
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"));
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:001"));
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:01"));
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"));
// Zero compression (2.2)
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:0:1", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd::1"));
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:0:1", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:0:1"));
Assert.assertEquals("2001:db8::1", IPv6Utils.canonize("2001:db8:0:0:0::1"));
Assert.assertEquals("2001:db8::1", IPv6Utils.canonize("2001:db8:0:0::1"));
Assert.assertEquals("2001:db8::1", IPv6Utils.canonize("2001:db8:0::1"));
Assert.assertEquals("2001:db8::1", IPv6Utils.canonize("2001:db8::1"));
Assert.assertEquals("2001:db8::aaaa:0:0:1", IPv6Utils.canonize("2001:db8::aaaa:0:0:1"));
Assert.assertEquals("2001:db8::aaaa:0:0:1", IPv6Utils.canonize("2001:db8:0:0:aaaa::1"));
// Uppercase or lowercase (2.3)
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"));
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:AAAA"));
Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa", IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:AaAa"));
// Some more zero compression for localhost addresses
Assert.assertEquals("::1", IPv6Utils.canonize("0:0:0:0:0:0:0:1"));
Assert.assertEquals("::1", IPv6Utils.canonize("0000:0:0:0:0:0:0:0001"));
Assert.assertEquals("::1", IPv6Utils.canonize("00:00:0:0:00:00:0:01"));
Assert.assertEquals("::1", IPv6Utils.canonize("::0001"));
Assert.assertEquals("::1", IPv6Utils.canonize("::1"));
// IPv6 unspecified address
Assert.assertEquals("::", IPv6Utils.canonize("0:0:0:0:0:0:0:0"));
Assert.assertEquals("::", IPv6Utils.canonize("0000:0:0:0:0:0:0:0000"));
Assert.assertEquals("::", IPv6Utils.canonize("00:00:0:0:00:00:0:00"));
Assert.assertEquals("::", IPv6Utils.canonize("::0000"));
Assert.assertEquals("::", IPv6Utils.canonize("::0"));
Assert.assertEquals("::", IPv6Utils.canonize("::"));
// Leading zeros (4.1)
Assert.assertEquals("2001:db8::1", IPv6Utils.canonize("2001:0db8::0001"));
// Shorten as much as possible (4.2.1)
Assert.assertEquals("2001:db8::2:1", IPv6Utils.canonize("2001:db8:0:0:0:0:2:1"));
Assert.assertEquals("2001:db8::", IPv6Utils.canonize("2001:db8:0:0:0:0:0:0"));
// Handling One 16-Bit 0 Field (4.2.2)
Assert.assertEquals("2001:db8:0:1:1:1:1:1", IPv6Utils.canonize("2001:db8:0:1:1:1:1:1"));
Assert.assertEquals("2001:db8:0:1:1:1:1:1", IPv6Utils.canonize("2001:db8::1:1:1:1:1"));
// Choice in Placement of "::" (4.2.3)
Assert.assertEquals("2001:0:0:1::1", IPv6Utils.canonize("2001:0:0:1:0:0:0:1"));
Assert.assertEquals("2001:db8::1:0:0:1", IPv6Utils.canonize("2001:db8:0:0:1:0:0:1"));
// IPv4 inside IPv6
Assert.assertEquals("::ffff:192.0.2.1", IPv6Utils.canonize("::ffff:192.0.2.1"));
Assert.assertEquals("::ffff:192.0.2.1", IPv6Utils.canonize("0:0:0:0:0:ffff:192.0.2.1"));
Assert.assertEquals("::192.0.2.1", IPv6Utils.canonize("::192.0.2.1"));
Assert.assertEquals("::192.0.2.1", IPv6Utils.canonize("0:0:0:0:0:0:192.0.2.1"));
// Zone ID
Assert.assertEquals("fe80::f0f0:c0c0:1919:1234%4", IPv6Utils.canonize("fe80::f0f0:c0c0:1919:1234%4"));
Assert.assertEquals("fe80::f0f0:c0c0:1919:1234%4", IPv6Utils.canonize("fe80:0:0:0:f0f0:c0c0:1919:1234%4"));
Assert.assertEquals("::%4", IPv6Utils.canonize("::%4"));
Assert.assertEquals("::%4", IPv6Utils.canonize("::0%4"));
Assert.assertEquals("::%4", IPv6Utils.canonize("0:0::0%4"));
Assert.assertEquals("::%4", IPv6Utils.canonize("0:0:0:0:0:0:0:0%4"));
Assert.assertEquals("::1%4", IPv6Utils.canonize("::1%4"));
Assert.assertEquals("::1%4", IPv6Utils.canonize("0:0::1%4"));
Assert.assertEquals("::1%4", IPv6Utils.canonize("0:0:0:0:0:0:0:1%4"));
Assert.assertEquals("::1%eth0", IPv6Utils.canonize("::1%eth0"));
Assert.assertEquals("::1%eth0", IPv6Utils.canonize("0:0::1%eth0"));
Assert.assertEquals("::1%eth0", IPv6Utils.canonize("0:0:0:0:0:0:0:1%eth0"));
// Hostname safety
Assert.assertEquals("www.apache.org", IPv6Utils.canonize("www.apache.org"));
Assert.assertEquals("ipv6.google.com", IPv6Utils.canonize("ipv6.google.com"));
}
}

View File

@@ -0,0 +1,182 @@
/*
* 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.
*/
package org.apache.tomcat.util.net;
import java.util.Arrays;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import org.apache.catalina.Context;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
import org.apache.tomcat.util.buf.ByteChunk;
/**
* The keys and certificates used in this file are all available in svn and were
* generated using a test CA the files for which are in the Tomcat PMC private
* repository since not all of them are AL2 licensed.
*/
public class TestClientCert extends TomcatBaseTest {
@Test
public void testClientCertGetWithoutPreemptive() throws Exception {
doTestClientCertGet(false);
}
@Test
public void testClientCertGetWithPreemptive() throws Exception {
doTestClientCertGet(true);
}
private void doTestClientCertGet(boolean preemptive) throws Exception {
Assume.assumeTrue("SSL renegotiation has to be supported for this test",
TesterSupport.isRenegotiationSupported(getTomcatInstance()));
if (preemptive) {
Tomcat tomcat = getTomcatInstance();
// Only one context deployed
Context c = (Context) tomcat.getHost().findChildren()[0];
// Enable pre-emptive auth
c.setPreemptiveAuthentication(true);
}
getTomcatInstance().start();
// Unprotected resource
ByteChunk res = getUrl("https://localhost:" + getPort() + "/unprotected");
int count = TesterSupport.getLastClientAuthRequestedIssuerCount();
if (log.isDebugEnabled()) {
log.debug("Last client KeyManager usage: " + TesterSupport.getLastClientAuthKeyManagerUsage() +
", " + count + " requested Issuers, first one: " +
(count > 0 ? TesterSupport.getLastClientAuthRequestedIssuer(0).getName() : "NONE"));
log.debug("Expected requested Issuer: " +
(preemptive ? TesterSupport.getClientAuthExpectedIssuer() : "NONE"));
}
if (preemptive) {
Assert.assertTrue("Checking requested client issuer against " +
TesterSupport.getClientAuthExpectedIssuer(),
TesterSupport.checkLastClientAuthRequestedIssuers());
Assert.assertEquals("OK-" + TesterSupport.ROLE, res.toString());
} else {
Assert.assertEquals(0, count);
Assert.assertEquals("OK", res.toString());
}
// Protected resource
res = getUrl("https://localhost:" + getPort() + "/protected");
if (log.isDebugEnabled()) {
count = TesterSupport.getLastClientAuthRequestedIssuerCount();
log.debug("Last client KeyManager usage: " + TesterSupport.getLastClientAuthKeyManagerUsage() +
", " + count + " requested Issuers, first one: " +
(count > 0 ? TesterSupport.getLastClientAuthRequestedIssuer(0).getName() : "NONE"));
log.debug("Expected requested Issuer: " + TesterSupport.getClientAuthExpectedIssuer());
}
Assert.assertTrue("Checking requested client issuer against " +
TesterSupport.getClientAuthExpectedIssuer(),
TesterSupport.checkLastClientAuthRequestedIssuers());
Assert.assertEquals("OK-" + TesterSupport.ROLE, res.toString());
}
@Test
public void testClientCertPostSmaller() throws Exception {
Tomcat tomcat = getTomcatInstance();
int bodySize = tomcat.getConnector().getMaxSavePostSize() / 2;
doTestClientCertPost(bodySize, false);
}
@Test
public void testClientCertPostSame() throws Exception {
Tomcat tomcat = getTomcatInstance();
int bodySize = tomcat.getConnector().getMaxSavePostSize();
doTestClientCertPost(bodySize, false);
}
@Test
public void testClientCertPostLarger() throws Exception {
Tomcat tomcat = getTomcatInstance();
int bodySize = tomcat.getConnector().getMaxSavePostSize() * 2;
doTestClientCertPost(bodySize, true);
}
private void doTestClientCertPost(int bodySize, boolean expectProtectedFail)
throws Exception {
Assume.assumeTrue("SSL renegotiation has to be supported for this test",
TesterSupport.isRenegotiationSupported(getTomcatInstance()));
getTomcatInstance().start();
byte[] body = new byte[bodySize];
Arrays.fill(body, TesterSupport.DATA);
// Unprotected resource
ByteChunk res = postUrl(body, "https://localhost:" + getPort() + "/unprotected");
int count = TesterSupport.getLastClientAuthRequestedIssuerCount();
if (log.isDebugEnabled()) {
log.debug("Last client KeyManager usage: " + TesterSupport.getLastClientAuthKeyManagerUsage() +
", " + count + " requested Issuers, first one: " +
(count > 0 ? TesterSupport.getLastClientAuthRequestedIssuer(0).getName() : "NONE"));
log.debug("Expected requested Issuer: NONE");
}
// Unprotected resource with no preemptive authentication
Assert.assertEquals(0, count);
// No authentication no need to buffer POST body during TLS handshake so
// no possibility of hitting buffer limit
Assert.assertEquals("OK-" + bodySize, res.toString());
// Protected resource
res.recycle();
int rc = postUrl(body, "https://localhost:" + getPort() + "/protected", res, null);
count = TesterSupport.getLastClientAuthRequestedIssuerCount();
if (log.isDebugEnabled()) {
log.debug("Last client KeyManager usage: " + TesterSupport.getLastClientAuthKeyManagerUsage() +
", " + count + " requested Issuers, first one: " +
(count > 0 ? TesterSupport.getLastClientAuthRequestedIssuer(0).getName() : "NONE"));
log.debug("Expected requested Issuer: " + TesterSupport.getClientAuthExpectedIssuer());
}
if (expectProtectedFail) {
Assert.assertEquals(401, rc);
// POST body buffer fails so TLS handshake never happens
Assert.assertEquals(0, count);
} else {
Assert.assertTrue("Checking requested client issuer against " +
TesterSupport.getClientAuthExpectedIssuer(),
TesterSupport.checkLastClientAuthRequestedIssuers());
Assert.assertEquals("OK-" + bodySize, res.toString());
}
}
@Override
public void setUp() throws Exception {
super.setUp();
Tomcat tomcat = getTomcatInstance();
TesterSupport.configureClientCertContext(tomcat);
TesterSupport.configureClientSsl();
}
}

View File

@@ -0,0 +1,84 @@
/*
* 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.
*/
package org.apache.tomcat.util.net;
import java.util.Arrays;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
import org.apache.tomcat.util.buf.ByteChunk;
/**
* The keys and certificates used in this file are all available in svn and were
* generated using a test CA the files for which are in the Tomcat PMC private
* repository since not all of them are AL2 licensed.
*
* The JSSE implementation of TLSv1.3 only supports authentication during the
* initial handshake. This test requires TLSv1.3 on client and server so it is
* skipped unless running on a Java version that supports TLSv1.3.
*/
public class TestClientCertTls13 extends TomcatBaseTest {
@Test
public void testClientCertGet() throws Exception {
Tomcat tomcat = getTomcatInstance();
tomcat.start();
ByteChunk res = getUrl("https://localhost:" + getPort() + "/protected");
Assert.assertEquals("OK-" + TesterSupport.ROLE, res.toString());
}
@Test
public void testClientCertPost() throws Exception {
Tomcat tomcat = getTomcatInstance();
tomcat.start();
int size = 32 * 1024;
byte[] body = new byte[size];
Arrays.fill(body, TesterSupport.DATA);
// Protected resource
ByteChunk res = new ByteChunk();
int rc = postUrl(body, "https://localhost:" + getPort() + "/protected", res, null);
Assert.assertEquals(200, rc);
Assert.assertEquals("OK-" + size, res.toString());
}
@Override
public void setUp() throws Exception {
super.setUp();
Tomcat tomcat = getTomcatInstance();
Connector connector = tomcat.getConnector();
Assume.assumeTrue(TesterSupport.isDefaultTLSProtocolForTesting13(connector));
TesterSupport.configureClientCertContext(tomcat);
// Need to override some of the previous settings
Assert.assertTrue(tomcat.getConnector().setProperty("sslEnabledProtocols", Constants.SSL_PROTO_TLSv1_3));
// And add force authentication to occur on the initial handshake
Assert.assertTrue(tomcat.getConnector().setProperty("clientAuth", "required"));
TesterSupport.configureClientSsl();
}
}

View File

@@ -0,0 +1,184 @@
/*
* 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.
*/
package org.apache.tomcat.util.net;
import java.io.File;
import java.net.SocketException;
import javax.net.ssl.SSLException;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
import org.apache.coyote.ProtocolHandler;
import org.apache.coyote.http11.AbstractHttp11JsseProtocol;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
import org.apache.tomcat.util.net.jsse.TesterBug50640SslImpl;
import org.apache.tomcat.websocket.server.WsContextListener;
/**
* The keys and certificates used in this file are all available in svn and were
* generated using a test CA the files for which are in the Tomcat PMC private
* repository since not all of them are AL2 licensed.
*/
public class TestCustomSsl extends TomcatBaseTest {
private static enum TrustType {
ALL,
CA,
NONE
}
@Test
public void testCustomSslImplementation() throws Exception {
TesterSupport.configureClientSsl();
Tomcat tomcat = getTomcatInstance();
Connector connector = tomcat.getConnector();
Assume.assumeFalse("This test is only for JSSE based SSL connectors",
connector.getProtocolHandlerClassName().contains("Apr"));
SSLHostConfig sslHostConfig = new SSLHostConfig();
SSLHostConfigCertificate certificate = new SSLHostConfigCertificate(sslHostConfig, Type.UNDEFINED);
sslHostConfig.addCertificate(certificate);
connector.addSslHostConfig(sslHostConfig);
Assert.assertTrue(connector.setProperty(
"sslImplementationName", "org.apache.tomcat.util.net.jsse.TesterBug50640SslImpl"));
// This setting will break ssl configuration unless the custom
// implementation is used.
sslHostConfig.setProtocols(TesterBug50640SslImpl.PROPERTY_VALUE);
sslHostConfig.setSslProtocol("tls");
File keystoreFile = new File(TesterSupport.LOCALHOST_RSA_JKS);
certificate.setCertificateKeystoreFile(keystoreFile.getAbsolutePath());
connector.setSecure(true);
Assert.assertTrue(connector.setProperty("SSLEnabled", "true"));
File appDir = new File(getBuildDirectory(), "webapps/examples");
Context ctxt = tomcat.addWebapp(
null, "/examples", appDir.getAbsolutePath());
ctxt.addApplicationListener(WsContextListener.class.getName());
tomcat.start();
ByteChunk res = getUrl("https://localhost:" + getPort() +
"/examples/servlets/servlet/HelloWorldExample");
Assert.assertTrue(res.toString().indexOf("<a href=\"../helloworld.html\">") > 0);
}
@Test
public void testCustomTrustManagerAll() throws Exception {
doTestCustomTrustManager(TrustType.ALL);
}
@Test
public void testCustomTrustManagerCA() throws Exception {
doTestCustomTrustManager(TrustType.CA);
}
@Test
public void testCustomTrustManagerNone() throws Exception {
doTestCustomTrustManager(TrustType.NONE);
}
private void doTestCustomTrustManager(TrustType trustType)
throws Exception {
Tomcat tomcat = getTomcatInstance();
Assume.assumeTrue("SSL renegotiation has to be supported for this test",
TesterSupport.isRenegotiationSupported(tomcat));
TesterSupport.configureClientCertContext(tomcat);
Connector connector = tomcat.getConnector();
// Override the defaults
ProtocolHandler handler = connector.getProtocolHandler();
if (handler instanceof AbstractHttp11JsseProtocol) {
connector.findSslHostConfigs()[0].setTruststoreFile(null);
} else {
// Unexpected
Assert.fail("Unexpected handler type");
}
if (trustType.equals(TrustType.ALL)) {
connector.findSslHostConfigs()[0].setTrustManagerClassName(
"org.apache.tomcat.util.net.TesterSupport$TrustAllCerts");
} else if (trustType.equals(TrustType.CA)) {
connector.findSslHostConfigs()[0].setTrustManagerClassName(
"org.apache.tomcat.util.net.TesterSupport$SequentialTrustManager");
}
// Start Tomcat
tomcat.start();
TesterSupport.configureClientSsl();
// Unprotected resource
ByteChunk res = getUrl("https://localhost:" + getPort() + "/unprotected");
Assert.assertEquals("OK", res.toString());
// Protected resource
res.recycle();
int rc = -1;
try {
rc = getUrl("https://localhost:" + getPort() + "/protected", res, null, null);
} catch (SocketException se) {
if (!trustType.equals(TrustType.NONE)) {
Assert.fail(se.getMessage());
se.printStackTrace();
}
} catch (SSLException he) {
if (!trustType.equals(TrustType.NONE)) {
Assert.fail(he.getMessage());
he.printStackTrace();
}
}
if (trustType.equals(TrustType.CA)) {
if (log.isDebugEnabled()) {
int count = TesterSupport.getLastClientAuthRequestedIssuerCount();
log.debug("Last client KeyManager usage: " + TesterSupport.getLastClientAuthKeyManagerUsage() +
", " + count + " requested Issuers, first one: " +
(count > 0 ? TesterSupport.getLastClientAuthRequestedIssuer(0).getName() : "NONE"));
log.debug("Expected requested Issuer: " + TesterSupport.getClientAuthExpectedIssuer());
}
Assert.assertTrue("Checking requested client issuer against " +
TesterSupport.getClientAuthExpectedIssuer(),
TesterSupport.checkLastClientAuthRequestedIssuers());
}
if (trustType.equals(TrustType.NONE)) {
Assert.assertTrue(rc != 200);
Assert.assertEquals("", res.toString());
} else {
Assert.assertEquals(200, rc);
Assert.assertEquals("OK-" + TesterSupport.ROLE, res.toString());
}
}
}

View File

@@ -0,0 +1,112 @@
/*
* 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.
*/
package org.apache.tomcat.util.net;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.apache.tomcat.util.net.openssl.OpenSSLConf;
import org.apache.tomcat.util.net.openssl.OpenSSLConfCmd;
import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
public class TestSSLHostConfig {
@Test
public void testCipher01() {
SSLHostConfig hc = new SSLHostConfig();
Cipher c = Cipher.TLS_RSA_WITH_NULL_MD5;
// Single JSSE name
hc.setCiphers(c.getJsseNames().iterator().next());
Assert.assertEquals(c.getOpenSSLAlias(), hc.getCiphers());
}
@Test
public void testCipher02() {
SSLHostConfig hc = new SSLHostConfig();
Cipher c1 = Cipher.TLS_RSA_WITH_NULL_MD5;
Cipher c2 = Cipher.TLS_RSA_WITH_NULL_SHA;
// Two JSSE names
hc.setCiphers(c1.getJsseNames().iterator().next() + "," +
c2.getJsseNames().iterator().next());
Assert.assertEquals(c1.getOpenSSLAlias() + ":" + c2.getOpenSSLAlias(), hc.getCiphers());
}
@Test
public void testCipher03() {
SSLHostConfig hc = new SSLHostConfig();
// Single OpenSSL alias
hc.setCiphers("ALL");
Assert.assertEquals("ALL", hc.getCiphers());
}
@Test
public void testCipher04() {
SSLHostConfig hc = new SSLHostConfig();
Cipher c = Cipher.TLS_RSA_WITH_NULL_MD5;
// Single OpenSSLName name
hc.setCiphers(c.getOpenSSLAlias());
Assert.assertEquals(c.getOpenSSLAlias(), hc.getCiphers());
}
@Test
public void testSerialization() throws IOException, ClassNotFoundException {
// Dummy OpenSSL command name/value pair
String name = "foo";
String value = "bar";
// Set up the object
SSLHostConfig sslHostConfig = new SSLHostConfig();
OpenSSLConf openSSLConf = new OpenSSLConf();
OpenSSLConfCmd openSSLConfCmd = new OpenSSLConfCmd();
openSSLConfCmd.setName(name);
openSSLConfCmd.setValue(value);
openSSLConf.addCmd(openSSLConfCmd);
sslHostConfig.setOpenSslConf(openSSLConf);
// Serialize
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(sslHostConfig);
oos.close();
// Deserialize
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
SSLHostConfig output = (SSLHostConfig) ois.readObject();
// Check values
List<OpenSSLConfCmd> commands = output.getOpenSslConf().getCommands();
Assert.assertEquals(1, commands.size());
OpenSSLConfCmd command = commands.get(0);
Assert.assertEquals(name, command.getName());
Assert.assertEquals(value, command.getValue());
}
}

View File

@@ -0,0 +1,349 @@
/*
* 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.
*/
package org.apache.tomcat.util.net;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.AprLifecycleListener;
import org.apache.catalina.core.StandardServer;
import org.apache.catalina.startup.TesterServlet;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.compat.JreCompat;
import org.apache.tomcat.util.net.SSLHostConfigCertificate.StoreType;
import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
import org.apache.tomcat.util.net.TesterSupport.ClientSSLSocketFactory;
/*
* Tests compatibility of JSSE and OpenSSL settings.
*/
@RunWith(Parameterized.class)
public class TestSSLHostConfigCompat extends TomcatBaseTest {
@Parameterized.Parameters(name = "{0}-{3}")
public static Collection<Object[]> parameters() {
List<Object[]> parameterSets = new ArrayList<>();
for (StoreType storeType : new StoreType[] { StoreType.KEYSTORE, StoreType.PEM } ) {
parameterSets.add(new Object[] {"NIO-JSSE", "org.apache.coyote.http11.Http11NioProtocol",
"org.apache.tomcat.util.net.jsse.JSSEImplementation", storeType});
parameterSets.add(new Object[] {"NIO-OpenSSL", "org.apache.coyote.http11.Http11NioProtocol",
"org.apache.tomcat.util.net.openssl.OpenSSLImplementation", storeType});
parameterSets.add(new Object[] { "APR/Native", "org.apache.coyote.http11.Http11AprProtocol",
"org.apache.tomcat.util.net.openssl.OpenSSLImplementation", storeType});
}
return parameterSets;
}
@Parameter(0)
public String connectorName;
@Parameter(1)
public String protocolName;
@Parameter(2)
public String sslImplementationName;
@Parameter(3)
public StoreType storeType;
private SSLHostConfig sslHostConfig = new SSLHostConfig();
@Test
public void testHostEC() throws Exception {
configureHostEC();
doTest();
}
@Test
public void testHostRSA() throws Exception {
configureHostRSA();
doTest();
}
@Test
public void testHostRSAandECwithDefaultClient() throws Exception {
configureHostRSA();
configureHostEC();
doTest();
}
/*
* This test and the next just swap the order in which the server certs are
* configured to ensure correct operation isn't dependent on order.
*/
@Test
public void testHostRSAandECwithRSAClient() throws Exception {
configureHostRSA();
configureHostEC();
// Configure cipher suite that requires an RSA certificate on the server
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
clientSSLSocketFactory.setCipher(new String[] {"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"});
doTest(false);
}
/*
* This test and the previous just swap the order in which the server certs
* are configured to ensure correct operation isn't dependent on order.
*/
@Test
public void testHostECandRSAwithRSAClient() throws Exception {
configureHostEC();
configureHostRSA();
// Configure cipher suite that requires an RSA certificate on the server
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
clientSSLSocketFactory.setCipher(new String[] {"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"});
doTest(false);
}
/*
* This test and the next just swap the order in which the server certs are
* configured to ensure correct operation isn't dependent on order.
*/
@Test
public void testHostRSAandECwithECClient() throws Exception {
configureHostRSA();
configureHostEC();
// Configure cipher suite that requires an EC certificate on the server
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
clientSSLSocketFactory.setCipher(new String[] {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"});
doTest(false);
}
/*
* This test and the previous just swap the order in which the server certs
* are configured to ensure correct operation isn't dependent on order.
*/
@Test
public void testHostECandRSAwithECClient() throws Exception {
configureHostEC();
configureHostRSA();
// Configure cipher suite that requires an EC certificate on the server
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
clientSSLSocketFactory.setCipher(new String[] {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"});
doTest(false);
}
@Test
public void testHostRSAwithRSAClient() throws Exception {
configureHostRSA();
// Configure cipher suite that requires an RSA certificate on the server
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
clientSSLSocketFactory.setCipher(new String[] {"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"});
doTest(false);
}
@Test(expected=javax.net.ssl.SSLHandshakeException.class)
public void testHostRSAwithECClient() throws Exception {
configureHostRSA();
// Configure cipher suite that requires an EC certificate on the server
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
clientSSLSocketFactory.setCipher(new String[] {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"});
doTest(false);
}
@Test
public void testHostRSAwithRSAandECClient() throws Exception {
configureHostRSA();
// Configure cipher suite that requires an EC certificate on the server
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
clientSSLSocketFactory.setCipher(new String[] {
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"});
doTest(false);
}
@Test(expected=javax.net.ssl.SSLHandshakeException.class)
public void testHostECwithRSAClient() throws Exception {
configureHostEC();
// Configure cipher suite that requires an RSA certificate on the server
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
clientSSLSocketFactory.setCipher(new String[] {"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"});
doTest(false);
}
@Test
public void testHostECwithECClient() throws Exception {
configureHostEC();
// Configure cipher suite that requires an EC certificate on the server
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
clientSSLSocketFactory.setCipher(new String[] {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"});
doTest(false);
}
@Test
public void testHostECwithRSAandECClient() throws Exception {
configureHostEC();
// Configure cipher suite that requires an RSA certificate on the server
ClientSSLSocketFactory clientSSLSocketFactory = TesterSupport.configureClientSsl();
clientSSLSocketFactory.setCipher(new String[] {
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"});
doTest(false);
}
private void configureHostRSA() {
switch (storeType) {
case KEYSTORE: {
SSLHostConfigCertificate sslHostConfigCertificateRsa = new SSLHostConfigCertificate(sslHostConfig, Type.RSA);
sslHostConfigCertificateRsa.setCertificateKeystoreFile(getPath(TesterSupport.LOCALHOST_RSA_JKS));
sslHostConfig.addCertificate(sslHostConfigCertificateRsa);
break;
}
case PEM: {
SSLHostConfigCertificate sslHostConfigCertificateRsa = new SSLHostConfigCertificate(sslHostConfig, Type.RSA);
sslHostConfigCertificateRsa.setCertificateFile(getPath(TesterSupport.LOCALHOST_RSA_CERT_PEM));
sslHostConfigCertificateRsa.setCertificateKeyFile(getPath(TesterSupport.LOCALHOST_RSA_KEY_PEM));
sslHostConfig.addCertificate(sslHostConfigCertificateRsa);
break;
}
}
}
private void configureHostEC() {
switch (storeType) {
case KEYSTORE: {
SSLHostConfigCertificate sslHostConfigCertificateEc = new SSLHostConfigCertificate(sslHostConfig, Type.EC);
sslHostConfigCertificateEc.setCertificateKeystoreFile(getPath(TesterSupport.LOCALHOST_EC_JKS));
sslHostConfig.addCertificate(sslHostConfigCertificateEc);
break;
}
case PEM: {
SSLHostConfigCertificate sslHostConfigCertificateEc = new SSLHostConfigCertificate(sslHostConfig, Type.EC);
sslHostConfigCertificateEc.setCertificateFile(getPath(TesterSupport.LOCALHOST_EC_CERT_PEM));
sslHostConfigCertificateEc.setCertificateKeyFile(getPath(TesterSupport.LOCALHOST_EC_KEY_PEM));
sslHostConfig.addCertificate(sslHostConfigCertificateEc);
break;
}
}
}
private void doTest() throws Exception {
// Use the default client TLS config
doTest(true);
}
private void doTest(boolean configureClientSsl) throws Exception {
if (configureClientSsl) {
TesterSupport.configureClientSsl();
}
Tomcat tomcat = getTomcatInstance();
tomcat.start();
// Check a request can be made
ByteChunk res = getUrl("https://localhost:" + getPort() + "/");
Assert.assertEquals("OK", res.toString());
}
@Override
protected String getProtocol() {
return protocolName;
}
@Override
public void setUp() throws Exception {
super.setUp();
AprLifecycleListener listener = new AprLifecycleListener();
Assume.assumeTrue(AprLifecycleListener.isAprAvailable());
Assume.assumeTrue(JreCompat.isJre8Available());
Tomcat tomcat = getTomcatInstance();
Connector connector = tomcat.getConnector();
connector.setPort(0);
connector.setScheme("https");
connector.setSecure(true);
Assert.assertTrue(connector.setProperty("SSLEnabled", "true"));
if (!connector.getProtocolHandlerClassName().contains("Apr")) {
// Skip this for APR. It is not supported.
Assert.assertTrue(connector.setProperty("sslImplementationName", sslImplementationName));
}
sslHostConfig.setProtocols("TLSv1.2");
connector.addSslHostConfig(sslHostConfig);
StandardServer server = (StandardServer) tomcat.getServer();
server.addLifecycleListener(listener);
// Simple webapp
Context ctxt = tomcat.addContext("", null);
Tomcat.addServlet(ctxt, "TesterServlet", new TesterServlet());
ctxt.addServletMappingDecoded("/*", "TesterServlet");
}
private static String getPath(String relativePath) {
File f = new File(relativePath);
return f.getAbsolutePath();
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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.
*/
package org.apache.tomcat.util.net;
import java.io.File;
import java.io.ObjectOutputStream;
import org.junit.Assert;
import org.junit.Test;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream;
import org.apache.tomcat.websocket.server.WsContextListener;
public class TestSSLHostConfigIntegration extends TomcatBaseTest {
@Test
public void testSslHostConfigIsSerializable() throws Exception {
Tomcat tomcat = getTomcatInstance();
File appDir = new File(getBuildDirectory(), "webapps/examples");
org.apache.catalina.Context ctxt = tomcat.addWebapp(
null, "/examples", appDir.getAbsolutePath());
ctxt.addApplicationListener(WsContextListener.class.getName());
TesterSupport.initSsl(tomcat);
tomcat.start();
SSLHostConfig[] sslHostConfigs =
tomcat.getConnector().getProtocolHandler().findSslHostConfigs();
boolean written = false;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
for (SSLHostConfig sslHostConfig : sslHostConfigs) {
oos.writeObject(sslHostConfig);
written = true;
}
}
Assert.assertTrue(written);
}
}

View File

@@ -0,0 +1,198 @@
/*
* 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.
*/
package org.apache.tomcat.util.net;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import org.apache.catalina.Context;
import org.apache.catalina.Wrapper;
import org.apache.catalina.startup.TesterServlet;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.websocket.server.WsContextListener;
/**
* The keys and certificates used in this file are all available in svn and were
* generated using a test CA the files for which are in the Tomcat PMC private
* repository since not all of them are AL2 licensed.
*/
public class TestSsl extends TomcatBaseTest {
@Test
public void testSimpleSsl() throws Exception {
TesterSupport.configureClientSsl();
Tomcat tomcat = getTomcatInstance();
File appDir = new File(getBuildDirectory(), "webapps/examples");
org.apache.catalina.Context ctxt = tomcat.addWebapp(
null, "/examples", appDir.getAbsolutePath());
ctxt.addApplicationListener(WsContextListener.class.getName());
TesterSupport.initSsl(tomcat);
tomcat.start();
ByteChunk res = getUrl("https://localhost:" + getPort() +
"/examples/servlets/servlet/HelloWorldExample");
Assert.assertTrue(res.toString().indexOf("<a href=\"../helloworld.html\">") > 0);
Assert.assertTrue("Checking no client issuer has been requested",
TesterSupport.getLastClientAuthRequestedIssuerCount() == 0);
}
@Test
public void testKeyPass() throws Exception {
TesterSupport.configureClientSsl();
Tomcat tomcat = getTomcatInstance();
File appDir = new File(getBuildDirectory(), "webapps/examples");
org.apache.catalina.Context ctxt = tomcat.addWebapp(
null, "/examples", appDir.getAbsolutePath());
ctxt.addApplicationListener(WsContextListener.class.getName());
TesterSupport.initSsl(tomcat, TesterSupport.LOCALHOST_KEYPASS_JKS,
TesterSupport.JKS_PASS, TesterSupport.JKS_KEY_PASS);
tomcat.start();
ByteChunk res = getUrl("https://localhost:" + getPort() +
"/examples/servlets/servlet/HelloWorldExample");
Assert.assertTrue(res.toString().indexOf("<a href=\"../helloworld.html\">") > 0);
Assert.assertTrue("Checking no client issuer has been requested",
TesterSupport.getLastClientAuthRequestedIssuerCount() == 0);
}
@Test
public void testRenegotiateWorks() throws Exception {
Tomcat tomcat = getTomcatInstance();
Assume.assumeTrue("SSL renegotiation has to be supported for this test",
TesterSupport.isClientRenegotiationSupported(getTomcatInstance()));
Context root = tomcat.addContext("", TEMP_DIR);
Wrapper w =
Tomcat.addServlet(root, "tester", new TesterServlet());
w.setAsyncSupported(true);
root.addServletMappingDecoded("/", "tester");
TesterSupport.initSsl(tomcat);
tomcat.start();
SSLContext sslCtx;
if (TesterSupport.isDefaultTLSProtocolForTesting13(tomcat.getConnector())) {
// Force TLS 1.2 if TLS 1.3 is available as JSSE's TLS 1.3
// implementation doesn't support Post Handshake Authentication
// which is required for this test to pass.
sslCtx = SSLContext.getInstance(Constants.SSL_PROTO_TLSv1_2);
} else {
sslCtx = SSLContext.getInstance(Constants.SSL_PROTO_TLS);
}
sslCtx.init(null, TesterSupport.getTrustManagers(), null);
SSLSocketFactory socketFactory = sslCtx.getSocketFactory();
SSLSocket socket = (SSLSocket) socketFactory.createSocket("localhost",
getPort());
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
Reader r = new InputStreamReader(is);
doRequest(os, r);
Assert.assertTrue("Checking no client issuer has been requested",
TesterSupport.getLastClientAuthRequestedIssuerCount() == 0);
TesterHandshakeListener listener = new TesterHandshakeListener();
socket.addHandshakeCompletedListener(listener);
socket.startHandshake();
doRequest(os, r);
// Handshake complete appears to be called asynchronously
int wait = 0;
while (wait < 5000 && !listener.isComplete()) {
wait += 50;
Thread.sleep(50);
}
Assert.assertTrue("Checking no client issuer has been requested",
TesterSupport.getLastClientAuthRequestedIssuerCount() == 0);
Assert.assertTrue(listener.isComplete());
System.out.println("Renegotiation completed after " + wait + " ms");
}
private void doRequest(OutputStream os, Reader r) throws IOException {
char[] expectedResponseLine = "HTTP/1.1 200 \r\n".toCharArray();
os.write("GET /tester HTTP/1.1\r\n".getBytes());
os.write("Host: localhost\r\n".getBytes());
os.write("Connection: Keep-Alive\r\n\r\n".getBytes());
os.flush();
// First check we get the expected response line
for (char c : expectedResponseLine) {
int read = r.read();
Assert.assertEquals(c, read);
}
// Skip to the end of the headers
char[] endOfHeaders ="\r\n\r\n".toCharArray();
int found = 0;
while (found != endOfHeaders.length) {
if (r.read() == endOfHeaders[found]) {
found++;
} else {
found = 0;
}
}
// Read the body
char[] expectedBody = "OK".toCharArray();
for (char c : expectedBody) {
int read = r.read();
Assert.assertEquals(c, read);
}
}
private static class TesterHandshakeListener implements HandshakeCompletedListener {
private volatile boolean complete = false;
@Override
public void handshakeCompleted(HandshakeCompletedEvent event) {
complete = true;
}
public boolean isComplete() {
return complete;
}
}
}

View File

@@ -0,0 +1,89 @@
/*
* 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.
*/
package org.apache.tomcat.util.net;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.junit.Assert;
import org.junit.Test;
import org.apache.tomcat.util.net.TLSClientHelloExtractor.ExtractorResult;
public class TestTLSClientHelloExtractor {
@Test
public void testInputNeedRead01() throws IOException {
ByteBuffer testInput = ByteBuffer.allocate(1024);
doTestInputNeedRead(testInput);
}
@Test(expected=IOException.class)
public void testInputMalformed01() throws IOException {
ByteBuffer testInput = ByteBuffer.allocate(1024);
// TLS handshake
testInput.put((byte) 22);
// TLS 1.0
testInput.put((byte) 3);
testInput.put((byte) 1);
// Record length 0 (correct, but not legal)
testInput.put((byte) 0);
testInput.put((byte) 0);
doTestInputNeedRead(testInput);
}
@Test(expected=IOException.class)
public void testInputMalformed02() throws IOException {
ByteBuffer testInput = ByteBuffer.allocate(1024);
// TLS handshake
testInput.put((byte) 22);
// TLS 1.0
testInput.put((byte) 3);
testInput.put((byte) 1);
// Record length 4
testInput.put((byte) 0);
testInput.put((byte) 4);
// Type 1 (client hello)
testInput.put((byte) 1);
// Client hello size 0 (correct, but not legal)
testInput.put((byte) 0);
testInput.put((byte) 0);
testInput.put((byte) 0);
doTestInputNeedRead(testInput);
}
public void doTestInputMalformed(ByteBuffer input) throws IOException {
TLSClientHelloExtractor extractor = new TLSClientHelloExtractor(input);
// Expect this to fail
extractor.getResult();
}
public void doTestInputNeedRead(ByteBuffer input) throws IOException {
TLSClientHelloExtractor extractor = new TLSClientHelloExtractor(input);
// Expect this to fail
ExtractorResult result = extractor.getResult();
Assert.assertEquals(ExtractorResult.NEED_READ, result);
}
}

View File

@@ -0,0 +1,198 @@
/*
* 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.
*/
package org.apache.tomcat.util.net;
import java.io.File;
import java.net.InetAddress;
import java.net.ServerSocket;
import org.junit.Assert;
import org.junit.Test;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
import org.apache.tomcat.jni.Address;
import org.apache.tomcat.jni.Error;
import org.apache.tomcat.jni.Library;
import org.apache.tomcat.jni.OS;
import org.apache.tomcat.jni.Pool;
import org.apache.tomcat.jni.Socket;
/**
* Test case for the Endpoint implementations. The testing framework will ensure
* that each implementation is tested.
*/
public class TestXxxEndpoint extends TomcatBaseTest {
private long createAprPool() {
// Create the pool for the server socket
try {
return Pool.create(0);
} catch (UnsatisfiedLinkError e) {
log.error("Could not create socket pool", e);
return 0;
}
}
private long createAprSocket(int port, long pool)
throws Exception {
/**
* Server socket "pointer".
*/
long serverSock = 0;
String address = InetAddress.getByName("localhost").getHostAddress();
// Create the APR address that will be bound
int family = Socket.APR_INET;
if (Library.APR_HAVE_IPV6) {
if (!OS.IS_BSD && !OS.IS_WIN32 && !OS.IS_WIN64)
family = Socket.APR_UNSPEC;
}
long inetAddress = 0;
try {
inetAddress = Address.info(address, family,
port, 0, pool);
// Create the APR server socket
serverSock = Socket.create(Address.getInfo(inetAddress).family,
Socket.SOCK_STREAM,
Socket.APR_PROTO_TCP, pool);
} catch (Exception ex) {
log.error("Could not create socket for address '" + address + "'");
return 0;
}
if (OS.IS_UNIX) {
Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1);
}
// Deal with the firewalls that tend to drop the inactive sockets
Socket.optSet(serverSock, Socket.APR_SO_KEEPALIVE, 1);
// Bind the server socket
int ret = Socket.bind(serverSock, inetAddress);
if (ret != 0) {
log.error("Could not bind: " + Error.strerror(ret));
throw (new Exception(Error.strerror(ret)));
}
return serverSock;
}
private void destroyAprSocket(long serverSock, long pool) {
if (serverSock != 0) {
Socket.shutdown(serverSock, Socket.APR_SHUTDOWN_READWRITE);
Socket.close(serverSock);
Socket.destroy(serverSock);
}
if (pool != 0) {
Pool.destroy(pool);
pool = 0;
}
}
@Test
public void testStartStopBindOnInit() throws Exception {
Tomcat tomcat = getTomcatInstance();
File appDir = new File(getBuildDirectory(), "webapps/examples");
tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath());
tomcat.start();
int port = getPort();
tomcat.getConnector().stop();
Exception e = null;
ServerSocket s = null;
long pool = 0;
long nativeSocket = 0;
boolean isApr = tomcat.getConnector().getProtocolHandlerClassName().contains("Apr");
try {
// This should throw an Exception
if (isApr) {
pool = createAprPool();
Assert.assertTrue(pool != 0);
nativeSocket = createAprSocket(port, pool);
Assert.assertTrue(nativeSocket != 0);
} else {
s = new ServerSocket(port, 100,
InetAddress.getByName("localhost"));
}
} catch (Exception e1) {
e = e1;
} finally {
try {
if (isApr) {
destroyAprSocket(nativeSocket, pool);
} else if (s != null) {
s.close();
}
} catch (Exception e2) { /* Ignore */ }
}
if (e != null) {
log.info("Exception was", e);
}
Assert.assertNotNull(e);
tomcat.getConnector().start();
}
@Test
public void testStartStopBindOnStart() throws Exception {
Tomcat tomcat = getTomcatInstance();
Connector c = tomcat.getConnector();
Assert.assertTrue(c.setProperty("bindOnInit", "false"));
File appDir = new File(getBuildDirectory(), "webapps/examples");
tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath());
tomcat.start();
int port = getPort();
tomcat.getConnector().stop();
Exception e = null;
ServerSocket s = null;
long pool = 0;
long nativeSocket = 0;
boolean isApr = tomcat.getConnector().getProtocolHandlerClassName().contains("Apr");
try {
// This should not throw an Exception
if (isApr) {
pool = createAprPool();
Assert.assertTrue(pool != 0);
nativeSocket = createAprSocket(port, pool);
Assert.assertTrue(nativeSocket != 0);
} else {
s = new ServerSocket(port, 100,
InetAddress.getByName("localhost"));
}
} catch (Exception e1) {
e = e1;
} finally {
try {
if (isApr) {
destroyAprSocket(nativeSocket, pool);
} else if (s != null) {
s.close();
}
} catch (Exception e2) { /* Ignore */ }
}
Assert.assertNull(e);
tomcat.getConnector().start();
}
}

View File

@@ -0,0 +1,698 @@
/*
* 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.
*/
package org.apache.tomcat.util.net;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Locale;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import javax.security.auth.x500.X500Principal;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Assert;
import org.apache.catalina.Context;
import org.apache.catalina.authenticator.SSLAuthenticator;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.AprLifecycleListener;
import org.apache.catalina.core.StandardServer;
import org.apache.catalina.startup.TesterMapRealm;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.jni.Library;
import org.apache.tomcat.jni.LibraryNotFoundError;
import org.apache.tomcat.jni.SSL;
import org.apache.tomcat.util.compat.JreCompat;
import org.apache.tomcat.util.descriptor.web.LoginConfig;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
public final class TesterSupport {
public static final String SSL_DIR = "test/org/apache/tomcat/util/net/";
public static final String CA_ALIAS = "ca";
public static final String CA_JKS = SSL_DIR + CA_ALIAS + ".jks";
public static final String CLIENT_ALIAS = "user1";
public static final String CLIENT_JKS = SSL_DIR + CLIENT_ALIAS + ".jks";
public static final String LOCALHOST_EC_JKS = SSL_DIR + "localhost-ec.jks";
public static final String LOCALHOST_RSA_JKS = SSL_DIR + "localhost-rsa.jks";
public static final String LOCALHOST_KEYPASS_JKS = SSL_DIR + "localhost-rsa-copy1.jks";
public static final String JKS_PASS = "changeit";
public static final String JKS_KEY_PASS = "tomcatpass";
public static final String CA_CERT_PEM = SSL_DIR + CA_ALIAS + "-cert.pem";
public static final String LOCALHOST_EC_CERT_PEM = SSL_DIR + "localhost-ec-cert.pem";
public static final String LOCALHOST_EC_KEY_PEM = SSL_DIR + "localhost-ec-key.pem";
public static final String LOCALHOST_RSA_CERT_PEM = SSL_DIR + "localhost-rsa-cert.pem";
public static final String LOCALHOST_RSA_KEY_PEM = SSL_DIR + "localhost-rsa-key.pem";
public static final boolean OPENSSL_AVAILABLE;
public static final int OPENSSL_VERSION;
public static final boolean TLSV13_AVAILABLE;
public static final String ROLE = "testrole";
private static String clientAuthExpectedIssuer;
private static String lastUsage = "NONE";
private static Principal[] lastRequestedIssuers = new Principal[0];
static {
boolean available = false;
int version = 0;
try {
Library.initialize(null);
available = true;
version = SSL.version();
Library.terminate();
} catch (Exception | LibraryNotFoundError ex) {
// Ignore
}
OPENSSL_AVAILABLE = available;
OPENSSL_VERSION = version;
available = false;
try {
SSLContext.getInstance(Constants.SSL_PROTO_TLSv1_3);
available = true;
} catch (NoSuchAlgorithmException ex) {
}
TLSV13_AVAILABLE = available;
}
public static boolean isOpensslAvailable() {
return OPENSSL_AVAILABLE;
}
public static int getOpensslVersion() {
return OPENSSL_VERSION;
}
public static boolean isTlsv13Available() {
return TLSV13_AVAILABLE;
}
public static void initSsl(Tomcat tomcat) {
initSsl(tomcat, LOCALHOST_RSA_JKS, null, null);
}
protected static void initSsl(Tomcat tomcat, String keystore,
String keystorePass, String keyPass) {
Connector connector = tomcat.getConnector();
connector.setSecure(true);
Assert.assertTrue(connector.setProperty("SSLEnabled", "true"));
SSLHostConfig sslHostConfig = new SSLHostConfig();
SSLHostConfigCertificate certificate = new SSLHostConfigCertificate(sslHostConfig, Type.UNDEFINED);
sslHostConfig.addCertificate(certificate);
connector.addSslHostConfig(sslHostConfig);
String protocol = tomcat.getConnector().getProtocolHandlerClassName();
if (!protocol.contains("Apr")) {
String sslImplementation = System.getProperty("tomcat.test.sslImplementation");
if (sslImplementation != null && !"${test.sslImplementation}".equals(sslImplementation)) {
StandardServer server = (StandardServer) tomcat.getServer();
AprLifecycleListener listener = new AprLifecycleListener();
listener.setSSLRandomSeed("/dev/urandom");
server.addLifecycleListener(listener);
connector.setAttribute("sslImplementationName", sslImplementation);
}
sslHostConfig.setSslProtocol("tls");
certificate.setCertificateKeystoreFile(new File(keystore).getAbsolutePath());
sslHostConfig.setTruststoreFile(new File(CA_JKS).getAbsolutePath());
if (keystorePass != null) {
certificate.setCertificateKeystorePassword(keystorePass);
}
if (keyPass != null) {
certificate.setCertificateKeyPassword(keyPass);
}
} else {
certificate.setCertificateFile(new File(LOCALHOST_RSA_CERT_PEM).getAbsolutePath());
certificate.setCertificateKeyFile(new File(LOCALHOST_RSA_KEY_PEM).getAbsolutePath());
sslHostConfig.setCaCertificateFile(new File(CA_CERT_PEM).getAbsolutePath());
}
}
protected static KeyManager[] getUser1KeyManagers() throws Exception {
KeyManagerFactory kmf = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
kmf.init(getKeyStore(CLIENT_JKS), JKS_PASS.toCharArray());
KeyManager[] managers = kmf.getKeyManagers();
KeyManager manager;
for (int i=0; i < managers.length; i++) {
manager = managers[i];
if (manager instanceof X509ExtendedKeyManager) {
managers[i] = new TrackingExtendedKeyManager((X509ExtendedKeyManager)manager);
} else if (manager instanceof X509KeyManager) {
managers[i] = new TrackingKeyManager((X509KeyManager)manager);
}
}
return managers;
}
protected static TrustManager[] getTrustManagers() throws Exception {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
tmf.init(getKeyStore(CA_JKS));
return tmf.getTrustManagers();
}
protected static ClientSSLSocketFactory configureClientSsl() {
ClientSSLSocketFactory clientSSLSocketFactory = null;
try {
SSLContext sc = SSLContext.getInstance(Constants.SSL_PROTO_TLS);
sc.init(TesterSupport.getUser1KeyManagers(),
TesterSupport.getTrustManagers(),
null);
clientSSLSocketFactory = new ClientSSLSocketFactory(sc.getSocketFactory());
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(clientSSLSocketFactory);
} catch (Exception e) {
e.printStackTrace();
}
return clientSSLSocketFactory;
}
private static KeyStore getKeyStore(String keystore) throws Exception {
File keystoreFile = new File(keystore);
KeyStore ks = KeyStore.getInstance("JKS");
try (InputStream is = new FileInputStream(keystoreFile)) {
ks.load(is, JKS_PASS.toCharArray());
}
return ks;
}
protected static boolean isMacOs() {
return System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("mac os x");
}
protected static boolean isRenegotiationSupported(Tomcat tomcat) {
String protocol = tomcat.getConnector().getProtocolHandlerClassName();
if (protocol.contains("Apr")) {
// Disabled by default in 1.1.20 windows binary (2010-07-27)
return false;
}
return true;
}
protected static boolean isClientRenegotiationSupported(Tomcat tomcat) {
String protocol = tomcat.getConnector().getProtocolHandlerClassName();
if (protocol.contains("Apr")) {
// Disabled by default in 1.1.20 windows binary (2010-07-27)
return false;
}
if (protocol.contains("NioProtocol") || (protocol.contains("Nio2Protocol") && isMacOs())) {
// Doesn't work on all platforms - see BZ 56448.
return false;
}
String sslImplementation = System.getProperty("tomcat.test.sslImplementation");
if (sslImplementation != null && !"${test.sslImplementation}".equals(sslImplementation)) {
// Assume custom SSL is not supporting this
return false;
}
return true;
}
protected static void configureClientCertContext(Tomcat tomcat) {
TesterSupport.initSsl(tomcat);
/* When running on Java 11, TLSv1.3 is enabled by default. The JSSE
* implementation of TLSv1.3 does not support
* certificateVerification="optional", a setting on which these tests
* depend.
* Java 7 does not enable TLSv1.1 or TLS1.2 by default
*
* Ensure these tests pass with all JREs from Java 7 onwards.
*/
if (JreCompat.isJre8Available()) {
tomcat.getConnector().findSslHostConfigs()[0].setProtocols(Constants.SSL_PROTO_TLSv1_2);
} else {
tomcat.getConnector().findSslHostConfigs()[0].setProtocols(Constants.SSL_PROTO_TLSv1);
}
// Need a web application with a protected and unprotected URL
// No file system docBase required
Context ctx = tomcat.addContext("", null);
Tomcat.addServlet(ctx, "simple", new SimpleServlet());
ctx.addServletMappingDecoded("/unprotected", "simple");
ctx.addServletMappingDecoded("/protected", "simple");
// Security constraints
SecurityCollection collection = new SecurityCollection();
collection.addPatternDecoded("/protected");
SecurityConstraint sc = new SecurityConstraint();
sc.addAuthRole(ROLE);
sc.addCollection(collection);
ctx.addConstraint(sc);
// Configure the Realm
TesterMapRealm realm = new TesterMapRealm();
// Get the CA subject the server should send us for client cert selection
try {
KeyStore ks = getKeyStore(CA_JKS);
X509Certificate cert = (X509Certificate)ks.getCertificate(CA_ALIAS);
clientAuthExpectedIssuer = cert.getSubjectDN().getName();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
String cn = "NOTFOUND";
try {
KeyStore ks = getKeyStore(CLIENT_JKS);
X509Certificate cert = (X509Certificate)ks.getCertificate(CLIENT_ALIAS);
cn = cert.getSubjectDN().getName();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
realm.addUser(cn, "not used");
realm.addUserRole(cn, ROLE);
ctx.setRealm(realm);
// Configure the authenticator
LoginConfig lc = new LoginConfig();
lc.setAuthMethod("CLIENT-CERT");
ctx.setLoginConfig(lc);
ctx.getPipeline().addValve(new SSLAuthenticator());
// Clear the tracking data
lastUsage = "NONE";
lastRequestedIssuers = new Principal[0];
}
protected static String getClientAuthExpectedIssuer() {
return clientAuthExpectedIssuer;
}
protected static void trackTrackingKeyManagers(@SuppressWarnings("unused") KeyManager wrapper,
@SuppressWarnings("unused") KeyManager wrapped, String usage, Principal[] issuers) {
lastUsage = usage;
lastRequestedIssuers = issuers;
}
protected static String getLastClientAuthKeyManagerUsage() {
return lastUsage;
}
protected static int getLastClientAuthRequestedIssuerCount() {
return lastRequestedIssuers == null ? 0 : lastRequestedIssuers.length;
}
protected static Principal getLastClientAuthRequestedIssuer(int index) {
return lastRequestedIssuers[index];
}
protected static boolean checkLastClientAuthRequestedIssuers() {
if (lastRequestedIssuers == null || lastRequestedIssuers.length != 1)
return false;
return (new X500Principal(clientAuthExpectedIssuer)).equals(
new X500Principal(lastRequestedIssuers[0].getName()));
}
public static final byte DATA = (byte)33;
public static class SimpleServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/plain");
resp.getWriter().print("OK");
if (req.isUserInRole(ROLE)) {
resp.getWriter().print("-" + ROLE);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Swallow any request body
int read = 0;
int len = 0;
byte[] buffer = new byte[4096];
InputStream is = req.getInputStream();
boolean contentOK = true;
while (len > -1) {
len = is.read(buffer);
read = read + len;
for (int i=0; i<len && contentOK; i++) {
contentOK = (buffer[i] == DATA);
}
}
// len will have been -1 on last iteration
read++;
// Report the number of bytes read
resp.setContentType("text/plain");
if (contentOK)
resp.getWriter().print("OK-" + read);
else
resp.getWriter().print("CONTENT-MISMATCH-" + read);
}
}
public static class TrackingKeyManager implements X509KeyManager {
private X509KeyManager manager = null;
public TrackingKeyManager(X509KeyManager manager) {
this.manager = manager;
}
@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
trackTrackingKeyManagers(this, manager, "chooseClientAlias", issuers);
return manager.chooseClientAlias(keyType, issuers, socket);
}
@Override
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
trackTrackingKeyManagers(this, manager, "chooseServerAlias", issuers);
return manager.chooseServerAlias(keyType, issuers, socket);
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
return manager.getCertificateChain(alias);
}
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
trackTrackingKeyManagers(this, manager, "getClientAliases", issuers);
return manager.getClientAliases(keyType, issuers);
}
@Override
public PrivateKey getPrivateKey(String alias) {
return manager.getPrivateKey(alias);
}
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
trackTrackingKeyManagers(this, manager, "getServerAliases", issuers);
return manager.getServerAliases(keyType, issuers);
}
}
public static class TrackingExtendedKeyManager extends X509ExtendedKeyManager {
private X509ExtendedKeyManager manager = null;
public TrackingExtendedKeyManager(X509ExtendedKeyManager manager) {
this.manager = manager;
}
@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
trackTrackingKeyManagers(this, manager, "chooseClientAlias", issuers);
return manager.chooseClientAlias(keyType, issuers, socket);
}
@Override
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
trackTrackingKeyManagers(this, manager, "chooseServerAlias", issuers);
return manager.chooseServerAlias(keyType, issuers, socket);
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
return manager.getCertificateChain(alias);
}
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
trackTrackingKeyManagers(this, manager, "getClientAliases", issuers);
return manager.getClientAliases(keyType, issuers);
}
@Override
public PrivateKey getPrivateKey(String alias) {
return manager.getPrivateKey(alias);
}
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
trackTrackingKeyManagers(this, manager, "getServerAliases", issuers);
return manager.getServerAliases(keyType, issuers);
}
@Override
public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) {
trackTrackingKeyManagers(this, manager, "chooseEngineClientAlias", issuers);
return manager.chooseEngineClientAlias(keyType, issuers, engine);
}
@Override
public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) {
trackTrackingKeyManagers(this, manager, "chooseEngineServerAlias", issuers);
return manager.chooseEngineServerAlias(keyType, issuers, engine);
}
}
public static class TrustAllCerts implements X509TrustManager {
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
@Override
public void checkClientTrusted(X509Certificate[] certs,
String authType) {
// NOOP - Trust everything
}
@Override
public void checkServerTrusted(X509Certificate[] certs,
String authType) {
// NOOP - Trust everything
}
}
public static class SequentialTrustManager implements X509TrustManager {
private static X509TrustManager[] tms;
private static X509Certificate[] certs;
static {
try {
TrustManager[] managers = getTrustManagers();
int mcount = 0;
int ccount = 0;
for (TrustManager tm : managers) {
if (tm instanceof X509TrustManager) {
mcount++;
ccount += ((X509TrustManager)tm).getAcceptedIssuers().length;
}
}
tms = new X509TrustManager[mcount];
certs = new X509Certificate[ccount];
mcount = 0;
ccount = 0;
for (TrustManager tm : managers) {
if (tm instanceof X509TrustManager) {
tms[mcount] = (X509TrustManager)tm;
mcount++;
for (X509Certificate cert : ((X509TrustManager)tm).getAcceptedIssuers()) {
certs[ccount] = cert;
ccount++;
}
}
}
} catch (Exception ex) {
tms = new X509TrustManager[1];
tms[0] = new TrustAllCerts();
certs = new X509Certificate[0];
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return certs;
}
@Override
public void checkClientTrusted(X509Certificate[] certs,
String authType) throws CertificateException {
boolean trust = false;
for (X509TrustManager tm : tms) {
try {
tm.checkClientTrusted(certs, authType);
trust = true;
} catch (CertificateException ex) {
// Ignore
}
}
if (!trust) {
throw new CertificateException();
}
}
@Override
public void checkServerTrusted(X509Certificate[] certs,
String authType) throws CertificateException {
boolean trust = false;
for (X509TrustManager tm : tms) {
try {
tm.checkServerTrusted(certs, authType);
trust = true;
} catch (CertificateException ex) {
// Ignore
}
}
if (!trust) {
throw new CertificateException();
}
}
}
public static class ClientSSLSocketFactory extends SSLSocketFactory {
private final SSLSocketFactory delegate;
private String[] ciphers = null;
public ClientSSLSocketFactory(SSLSocketFactory delegate) {
this.delegate = delegate;
}
/**
* Forces the use of the specified cipher.
*
* @param ciphers Array of standard JSSE names of ciphers to use
*/
public void setCipher(String[] ciphers) {
this.ciphers = ciphers;
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
Socket result = delegate.createSocket(s, host, port, autoClose);
reconfigureSocket(result);
return result;
}
@Override
public String[] getDefaultCipherSuites() {
return delegate.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return delegate.getSupportedCipherSuites();
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
Socket result = delegate.createSocket(host, port);
reconfigureSocket(result);
return result;
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
Socket result = delegate.createSocket(host, port);
reconfigureSocket(result);
return result;
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
throws IOException, UnknownHostException {
Socket result = delegate.createSocket(host, port, localHost, localPort);
reconfigureSocket(result);
return result;
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
throws IOException {
Socket result = delegate.createSocket(address, port, localAddress, localPort);
reconfigureSocket(result);
return result;
}
private Socket reconfigureSocket(Socket socket) {
if (ciphers != null) {
((SSLSocket) socket).setEnabledCipherSuites(ciphers);
}
return socket;
}
}
/*
* We want to use TLS 1.3 where we can but this requires TLS 1.3 to be
* supported on the client and the server.
*/
public static String getDefaultTLSProtocolForTesting(Connector connector) {
// Clients always use JSSE
if (!TLSV13_AVAILABLE) {
// Client doesn't support TLS 1.3 so we have to use TLS 1.2
return Constants.SSL_PROTO_TLSv1_2;
}
if (connector.getProtocolHandlerClassName().contains("Apr")) {
// APR connector so OpenSSL is used for TLS.
if (SSL.version() >= 0x1010100f) {
return Constants.SSL_PROTO_TLSv1_3;
} else {
return Constants.SSL_PROTO_TLSv1_2;
}
} else {
// NIO or NIO2. Tests do not use JSSE+OpenSSL so JSSE will be used.
// Due to check above, it is known that TLS 1.3 is available
return Constants.SSL_PROTO_TLSv1_3;
}
}
public static boolean isDefaultTLSProtocolForTesting13(Connector connector) {
return Constants.SSL_PROTO_TLSv1_3.equals(
TesterSupport.getDefaultTLSProtocolForTesting(connector));
}
}

View File

@@ -0,0 +1,38 @@
-----BEGIN CERTIFICATE-----
MIIGpzCCBI+gAwIBAgIJAL51xu6EZW62MA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD
VQQGEwJVUzELMAkGA1UECBMCTUExEjAQBgNVBAcTCVdha2VmaWVsZDEnMCUGA1UE
ChMeVGhlIEFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9uMRowGAYDVQQLExFBcGFj
aGUgVG9tY2F0IFBNQzEeMBwGA1UEAxMVQXBhY2hlIFRvbWNhdCBUZXN0IENBMB4X
DTE3MDgwODEwMzYzNloXDTI3MDgwNjEwMzYzNlowgZMxCzAJBgNVBAYTAlVTMQsw
CQYDVQQIEwJNQTESMBAGA1UEBxMJV2FrZWZpZWxkMScwJQYDVQQKEx5UaGUgQXBh
Y2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xGjAYBgNVBAsTEUFwYWNoZSBUb21jYXQg
UE1DMR4wHAYDVQQDExVBcGFjaGUgVG9tY2F0IFRlc3QgQ0EwggIiMA0GCSqGSIb3
DQEBAQUAA4ICDwAwggIKAoICAQCuokXuzdQ8HToRVcL07AdxHW9WmaMpcPWb/vyQ
dcuha+JXJ9Wu+d7fpxppeuxnjDmDCZNo0kimI7nYIEDMd3WVen75aoMZnQ7+vN/G
ZQXxzSPz2vzTZyEETAqs7DsGwO5CK2y5sWKl57+QCz/N+xM7EwOyNkmt+7xI1eQ+
z2sUNLRMK7abom8nm/wVftGAXIiribmTqukoxjr8dpEDg77VCy9eqe6kcil6Fvnr
mYrJqmrwzGldUlw4jqHl1IJnJ5z281vzzQ0U5ULeiuBpDGXcOHoaH8zYxilBVpPu
RDRBOcX17e5NouZtDTFemkJq5ns3PDt+WjJvuYNSELLBbnP+S1V6mt+MU9PsF6Td
lVZZxxFD9hPYqAzymwJGzTKbE8juZruQswL4iftyELmLPjIsetVtXifsUNay6CfD
r5sN6r+KLrhJWUqhii2mH1jx4cLmlf308TOc80TldvvI9cfrb596954cEE+7dlaU
vnRbBAeVNHNHl5e68fvwpKgtvQhtg1rZ2w1foSkAyyNRkYrUZKe4ztUx9E2w9qIm
3OkZyMcPTKYkBVahR6K1bCo69uaUrxY4NaYlPfKdJmGfio/J2WGdqLq9na4iHRyY
pb5zKvYmH9cNpmn5V42yhmX7tjMJzUyWw8KxXpE/qEVB2wl11wNguEL8CaZy+3u0
iaCqbQIDAQABo4H7MIH4MB0GA1UdDgQWBBQA8phNISwAPECbhPTeKvAm7jIOnzCB
yAYDVR0jBIHAMIG9gBQA8phNISwAPECbhPTeKvAm7jIOn6GBmaSBljCBkzELMAkG
A1UEBhMCVVMxCzAJBgNVBAgTAk1BMRIwEAYDVQQHEwlXYWtlZmllbGQxJzAlBgNV
BAoTHlRoZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbjEaMBgGA1UECxMRQXBh
Y2hlIFRvbWNhdCBQTUMxHjAcBgNVBAMTFUFwYWNoZSBUb21jYXQgVGVzdCBDQYIJ
AL51xu6EZW62MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAAJx4rzn
rtrcic/F0keS2BSazERFmRlSOlHUsREk+6fq35h7ktnijBHsPXyLEPa5w9x5qJZf
a2zFGiiiHqRBiX1E8JhKR6jjcX3D3VODfLomXWInHgEDcwNNcnvspG0RUX2jUh7m
p1i1c32r1s51P0AEB4zmT6KZ7gAZThqwtkpf6FQXmKdVXQFbf8EP0+6HFpHhV4lc
Ee4tDGJnc8X59Yzhu2rg8tF8OmNwcccTXthCH4I/4wymbw6YLg/B/V7AXH1/lui3
B15MKabYgZOU3TeOmQ9sqFPztekEKe+sE3Mvdf90Fh4EBZCENWULGUJE9uVJuT8S
2WVGOMmIkDlMP0t8Wnb3gMwUzhGyWp2FjzixVg8vS85ZE5wX4kGPD6nx+cAPDKrd
j3TCdr0VHoxVoGkzvijDjf6+aNhHp87VYSOZDQh1ToNgDFHum362iXt7n+ppu3u4
LDG3c1ztmUjgGrki+bQvnVyeYSprNWO1houo7xvZ61gWtzo1jwvcOwU0NxWtQMAg
NLZeketZSAL2834Xhkj1tjP2HT5HffkYbg6QRWKPYk/vBUKU40VilDCXf2ieOR9A
UtbcjjB5dRbR0CTnbwu33XeuhqobhaaAbp9gGt71WnOZpKIrkvVG3Z+YLpotRiYd
cl3dVVqvg/CTCpwd/VOOAmW1ynLpflLR8rH/
-----END CERTIFICATE-----

Binary file not shown.

View File

@@ -0,0 +1,45 @@
/*
* 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.
*/
package org.apache.tomcat.util.net.jsse;
import org.apache.tomcat.util.compat.JreCompat;
import org.apache.tomcat.util.net.Constants;
import org.apache.tomcat.util.net.SSLHostConfig;
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
import org.apache.tomcat.util.net.SSLUtil;
public class TesterBug50640SslImpl extends JSSEImplementation {
public static final String PROPERTY_VALUE = "magic";
@Override
public SSLUtil getSSLUtil(SSLHostConfigCertificate certificate) {
SSLHostConfig sslHostConfig = certificate.getSSLHostConfig();
if (sslHostConfig.getProtocols().size() == 1 &&
sslHostConfig.getProtocols().contains(PROPERTY_VALUE)) {
if (JreCompat.isJre8Available()) {
sslHostConfig.setProtocols(Constants.SSL_PROTO_TLSv1_2);
} else {
sslHostConfig.setProtocols(Constants.SSL_PROTO_TLSv1);
}
return super.getSSLUtil(certificate);
} else {
return null;
}
}
}

View File

@@ -0,0 +1,28 @@
================================================================================
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.
================================================================================
ca.jks (changeit)
ca CN=Apache Tomcat Test CA
localhost-rsa.jks (changeit)
tomcat CN=localhost
localhost-rsa-copy1.jks (changeit)
tomcat CN=localhost (tomcatpass)
user1.jks (changeit)
user1 CN=user1

View File

@@ -0,0 +1,86 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4098 (0x1002)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=MA, L=Wakefield, O=The Apache Software Foundation, OU=Apache Tomcat PMC, CN=Apache Tomcat Test CA
Validity
Not Before: Feb 15 19:32:18 2019 GMT
Not After : Feb 14 19:32:18 2021 GMT
Subject: C=US, ST=MA, L=Wakefield, O=The Apache Software Foundation, OU=Apache Tomcat PMC, CN=localhost
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:10:cc:24:b7:0c:2a:fe:a6:af:ea:b2:dc:26:f1:
81:06:ae:0b:eb:f0:c0:5f:a3:ee:5a:e3:d3:7c:02:
b0:58:6c:47:0e:6e:08:ac:30:e1:76:e5:9c:06:80:
af:42:ce:a7:6f:49:b5:ec:95:08:b1:a9:e3:7a:f7:
84:4f:e2:05:60
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
F8:98:B3:3A:75:F3:09:EB:FF:CC:6E:26:39:F0:B5:FF:1F:0F:FB:01
X509v3 Authority Key Identifier:
keyid:00:F2:98:4D:21:2C:00:3C:40:9B:84:F4:DE:2A:F0:26:EE:32:0E:9F
Signature Algorithm: sha256WithRSAEncryption
66:3f:a4:8e:4b:e0:3c:a2:54:d3:8d:6a:6d:83:fe:02:13:a8:
79:41:55:68:33:7a:13:84:2f:92:db:aa:06:ab:4c:69:a7:fe:
47:2f:31:a0:16:e8:cb:df:a8:d7:b3:21:27:2b:51:e2:77:05:
65:40:17:40:ff:9c:b8:3c:9f:c7:bf:65:8e:00:6f:ce:01:6d:
30:37:84:96:bd:78:11:26:be:27:22:53:67:c8:ac:cb:04:cb:
e2:96:a3:9e:a3:16:af:bf:97:be:c6:3d:0a:0f:1d:e9:45:0b:
ea:77:47:a7:d5:79:b2:5a:bc:83:4c:8c:2a:ca:b7:4c:0c:d4:
17:d5:24:b1:b1:5b:2c:6e:59:5d:30:40:b5:72:6f:3a:b1:f4:
f9:0d:7e:b9:aa:99:26:19:21:b0:07:4d:49:c3:e7:c2:3d:c8:
98:62:cd:b6:d5:9a:21:f8:c7:b0:1a:72:59:02:80:0f:83:af:
d7:3b:8a:7e:53:38:8c:0d:e9:03:9d:c8:f9:1d:5c:82:7f:49:
8d:87:d3:89:69:a1:39:d3:fd:04:17:e5:63:af:55:02:ef:60:
d7:70:1d:60:6c:aa:53:43:13:f1:82:f6:b6:41:71:7b:38:ff:
82:78:73:73:11:e7:48:2f:f8:e8:77:27:7a:0f:a3:14:b0:33:
f9:aa:65:0c:8f:69:3b:2f:ee:b3:51:d6:5d:8a:67:80:47:1e:
a3:bd:d2:03:c3:62:45:1a:ac:dd:79:2e:84:a7:3d:8a:27:89:
c4:31:cc:1c:0b:37:a6:9d:a4:e4:65:03:8b:a3:5a:63:60:fb:
b9:7b:44:7f:8d:6a:74:9f:52:0e:b8:e7:12:52:98:5f:e9:34:
20:5a:f6:b7:15:a1:81:5e:f4:18:6c:18:c7:e8:dc:64:f8:d1:
a2:6f:98:a6:fd:36:e8:be:e7:a8:3f:a5:cb:de:1f:8f:ef:4a:
29:ee:69:f3:81:cd:ce:ec:5f:d7:b8:61:c1:41:4b:b0:49:5c:
29:eb:dd:e8:a6:54:4c:61:72:af:9c:50:da:16:1d:da:14:c9:
5f:8a:ae:2a:41:3b:9d:1e:72:7d:c8:eb:28:f2:a5:49:9b:ca:
0c:38:88:09:b3:5f:a9:83:13:6a:93:03:f9:3c:92:22:b8:cb:
ad:ba:dc:9b:6d:a6:9e:b0:d5:5a:57:ea:ae:f7:e9:8f:03:c2:
24:80:f8:50:21:94:7c:58:ac:b0:86:58:13:f2:d4:ef:f3:c1:
53:96:88:f9:dd:19:a7:83:fe:a9:d1:0a:1c:d0:10:23:6e:24:
47:41:3b:d4:dd:a1:06:2d:8a:ba:51:ef:34:e7:81:f0:94:51:
28:3a:44:8e:de:25:fa:e3
-----BEGIN CERTIFICATE-----
MIIESDCCAjCgAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwgZMxCzAJBgNVBAYTAlVT
MQswCQYDVQQIEwJNQTESMBAGA1UEBxMJV2FrZWZpZWxkMScwJQYDVQQKEx5UaGUg
QXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xGjAYBgNVBAsTEUFwYWNoZSBUb21j
YXQgUE1DMR4wHAYDVQQDExVBcGFjaGUgVG9tY2F0IFRlc3QgQ0EwHhcNMTkwMjE1
MTkzMjE4WhcNMjEwMjE0MTkzMjE4WjCBhzELMAkGA1UEBhMCVVMxCzAJBgNVBAgM
Ak1BMRIwEAYDVQQHDAlXYWtlZmllbGQxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29m
dHdhcmUgRm91bmRhdGlvbjEaMBgGA1UECwwRQXBhY2hlIFRvbWNhdCBQTUMxEjAQ
BgNVBAMMCWxvY2FsaG9zdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBDMJLcM
Kv6mr+qy3CbxgQauC+vwwF+j7lrj03wCsFhsRw5uCKww4XblnAaAr0LOp29JteyV
CLGp43r3hE/iBWCjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5T
U0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBT4mLM6dfMJ6//MbiY5
8LX/Hw/7ATAfBgNVHSMEGDAWgBQA8phNISwAPECbhPTeKvAm7jIOnzANBgkqhkiG
9w0BAQsFAAOCAgEAZj+kjkvgPKJU041qbYP+AhOoeUFVaDN6E4QvktuqBqtMaaf+
Ry8xoBboy9+o17MhJytR4ncFZUAXQP+cuDyfx79ljgBvzgFtMDeElr14ESa+JyJT
Z8isywTL4pajnqMWr7+XvsY9Cg8d6UUL6ndHp9V5slq8g0yMKsq3TAzUF9UksbFb
LG5ZXTBAtXJvOrH0+Q1+uaqZJhkhsAdNScPnwj3ImGLNttWaIfjHsBpyWQKAD4Ov
1zuKflM4jA3pA53I+R1cgn9JjYfTiWmhOdP9BBflY69VAu9g13AdYGyqU0MT8YL2
tkFxezj/gnhzcxHnSC/46Hcneg+jFLAz+aplDI9pOy/us1HWXYpngEceo73SA8Ni
RRqs3XkuhKc9iieJxDHMHAs3pp2k5GUDi6NaY2D7uXtEf41qdJ9SDrjnElKYX+k0
IFr2txWhgV70GGwYx+jcZPjRom+Ypv026L7nqD+ly94fj+9KKe5p84HNzuxf17hh
wUFLsElcKevd6KZUTGFyr5xQ2hYd2hTJX4quKkE7nR5yfcjrKPKlSZvKDDiICbNf
qYMTapMD+TySIrjLrbrcm22mnrDVWlfqrvfpjwPCJID4UCGUfFissIZYE/LU7/PB
U5aI+d0Zp4P+qdEKHNAQI24kR0E71N2hBi2KulHvNOeB8JRRKDpEjt4l+uM=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg0U7ZRpeTEzVDXCCP
oKwgWnN0tf7CMaE9dJmLIPpNgnChRANCAAQQzCS3DCr+pq/qstwm8YEGrgvr8MBf
o+5a49N8ArBYbEcObgisMOF25ZwGgK9CzqdvSbXslQixqeN694RP4gVg
-----END PRIVATE KEY-----

Binary file not shown.

View File

@@ -0,0 +1,109 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4102 (0x1006)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=MA, L=Wakefield, O=The Apache Software Foundation, OU=Apache Tomcat PMC, CN=Apache Tomcat Test CA
Validity
Not Before: Aug 7 20:30:28 2019 GMT
Not After : Aug 6 20:30:28 2021 GMT
Subject: C=US, ST=MA, L=Wakefield, O=The Apache Software Foundation, OU=Apache Tomcat PMC, CN=localhost
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:cf:e2:56:a6:67:a6:e8:e7:f3:94:86:6e:f9:06:
46:cf:20:66:b5:cd:b1:c7:d6:50:ea:4d:46:44:ed:
45:65:ea:b6:9b:2e:49:a5:25:c1:8e:36:f6:2c:bc:
8e:09:35:0b:2f:43:70:73:07:47:1d:78:a1:12:e9:
56:5d:ab:84:15:16:0e:38:01:bb:81:87:2d:c4:3b:
dc:2e:4a:e1:d4:66:1b:ce:87:2c:a9:b8:e3:aa:80:
75:79:b1:98:f3:dd:df:66:d0:0d:e1:06:d8:6c:6c:
50:f0:00:80:32:70:55:7b:dd:eb:ae:f2:6a:bf:93:
3d:15:e1:25:f8:75:ce:d8:46:dc:c4:6b:ee:f9:f5:
93:39:ad:90:47:15:4b:fa:ca:5b:fe:ca:1b:29:8a:
74:19:2a:cb:1e:4f:20:d9:74:75:24:a0:06:d1:3a:
ed:9b:88:87:f3:1b:0f:a6:14:67:e9:ed:47:2e:a1:
25:6a:c2:97:04:13:f4:9f:62:38:cd:5a:e7:ad:c2:
64:2c:8f:9c:3d:04:58:12:42:e5:0c:8e:8c:ce:78:
3d:60:38:ce:06:ff:9c:ea:9c:c9:0f:73:90:b2:1a:
4a:16:99:c9:fe:95:88:7b:3c:7f:19:d0:26:27:11:
78:f9:92:5c:b4:f5:d4:cb:b0:84:0c:74:37:3d:87:
1a:0b
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
0D:86:88:1D:07:59:CE:14:B4:89:81:58:C6:0B:FF:4C:CA:25:52:80
X509v3 Authority Key Identifier:
keyid:00:F2:98:4D:21:2C:00:3C:40:9B:84:F4:DE:2A:F0:26:EE:32:0E:9F
Authority Information Access:
OCSP - URI:http://127.0.0.1:8888
X509v3 Subject Alternative Name:
DNS:localhost, IP Address:127.0.0.1
Signature Algorithm: sha256WithRSAEncryption
7d:dc:b1:0f:dd:34:df:26:63:73:02:8a:d6:39:64:73:c3:fc:
40:75:26:b6:9b:42:72:af:c9:63:41:68:d0:78:c7:47:ef:c2:
44:5a:b3:58:95:a3:2c:f3:b1:f4:a3:3d:0b:94:ff:b4:97:6a:
e9:4b:4b:c2:3a:f6:36:43:af:ee:2f:39:3e:f2:5f:2c:a2:b7:
43:3c:13:42:d8:4e:e0:36:bc:23:c5:43:88:46:92:f7:77:14:
67:73:14:5b:43:0e:3d:b5:1a:69:e9:ca:84:08:20:27:9f:23:
4d:60:db:cb:98:4a:b3:3e:71:e6:e8:a1:11:1c:7e:7e:43:fb:
6d:a5:41:c0:7e:3f:84:ed:06:28:dc:aa:80:17:76:ec:8a:e6:
65:45:21:85:13:48:e0:5b:87:c8:2a:1a:0f:37:0f:2a:64:53:
a8:e3:49:04:84:88:fe:8b:a2:3c:cc:41:c7:c0:ad:26:d6:e1:
67:69:9a:50:c7:eb:3d:1c:7f:da:88:08:24:14:6e:a1:ab:3e:
77:3f:88:12:55:98:97:9f:db:ad:09:e2:20:fe:8d:1f:ea:4f:
46:7e:d8:aa:ba:14:bd:a8:c2:6f:1b:47:62:d9:05:ca:c7:30:
7b:1e:95:2e:55:10:1d:b1:e3:44:95:07:25:6e:8c:9d:69:5b:
5c:ad:5f:56:27:e8:60:9f:d2:f4:64:7f:f7:8f:dc:bb:ee:bf:
be:0b:ea:34:9b:37:de:f0:5c:e0:64:c2:52:42:a6:0d:20:7d:
78:34:42:c1:1c:43:a1:98:e8:48:7b:92:49:2b:d9:63:91:6a:
70:02:d0:1b:a5:2a:ee:e5:1b:12:4f:cb:c9:e7:18:ae:66:f5:
04:d9:d2:68:95:c1:31:fe:57:9d:51:f5:fc:ed:43:3b:79:bf:
c3:9d:85:68:d8:98:a5:3c:a2:bb:fb:5b:19:5b:de:f0:7e:c8:
5e:47:ba:5d:8a:5b:44:f1:44:54:64:c0:da:95:a6:f0:bf:a9:
3f:5d:4c:72:97:86:ae:1e:0d:cd:20:4b:85:e0:4e:26:4d:29:
4e:96:43:b0:fd:30:5f:53:24:97:bc:35:d8:31:4b:6c:ea:a7:
f9:64:f9:cb:a0:14:c4:fc:54:78:13:52:b5:06:8f:7a:c2:00:
14:97:18:06:ef:bc:2f:2a:31:fc:11:25:7f:47:e3:3b:54:e7:
46:62:78:ba:52:07:32:41:48:9d:47:bd:1c:f4:eb:49:11:42:
40:9c:36:5a:e0:84:bd:09:44:91:bb:5c:d1:c4:28:6a:68:34:
f9:2c:22:b7:fc:43:bb:c4:96:02:ce:73:43:be:de:02:9c:e1:
d2:2a:4a:76:19:d6:3f:b0
-----BEGIN CERTIFICATE-----
MIIFZDCCA0ygAwIBAgICEAYwDQYJKoZIhvcNAQELBQAwgZMxCzAJBgNVBAYTAlVT
MQswCQYDVQQIEwJNQTESMBAGA1UEBxMJV2FrZWZpZWxkMScwJQYDVQQKEx5UaGUg
QXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xGjAYBgNVBAsTEUFwYWNoZSBUb21j
YXQgUE1DMR4wHAYDVQQDExVBcGFjaGUgVG9tY2F0IFRlc3QgQ0EwHhcNMTkwODA3
MjAzMDI4WhcNMjEwODA2MjAzMDI4WjCBhzELMAkGA1UEBhMCVVMxCzAJBgNVBAgT
Ak1BMRIwEAYDVQQHEwlXYWtlZmllbGQxJzAlBgNVBAoTHlRoZSBBcGFjaGUgU29m
dHdhcmUgRm91bmRhdGlvbjEaMBgGA1UECxMRQXBhY2hlIFRvbWNhdCBQTUMxEjAQ
BgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AM/iVqZnpujn85SGbvkGRs8gZrXNscfWUOpNRkTtRWXqtpsuSaUlwY429iy8jgk1
Cy9DcHMHRx14oRLpVl2rhBUWDjgBu4GHLcQ73C5K4dRmG86HLKm446qAdXmxmPPd
32bQDeEG2GxsUPAAgDJwVXvd667yar+TPRXhJfh1zthG3MRr7vn1kzmtkEcVS/rK
W/7KGymKdBkqyx5PINl0dSSgBtE67ZuIh/MbD6YUZ+ntRy6hJWrClwQT9J9iOM1a
563CZCyPnD0EWBJC5QyOjM54PWA4zgb/nOqcyQ9zkLIaShaZyf6ViHs8fxnQJicR
ePmSXLT11MuwhAx0Nz2HGgsCAwEAAaOByzCByDAJBgNVHRMEAjAAMCwGCWCGSAGG
+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU
DYaIHQdZzhS0iYFYxgv/TMolUoAwHwYDVR0jBBgwFoAUAPKYTSEsADxAm4T03irw
Ju4yDp8wMQYIKwYBBQUHAQEEJTAjMCEGCCsGAQUFBzABhhVodHRwOi8vMTI3LjAu
MC4xOjg4ODgwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEB
CwUAA4ICAQB93LEP3TTfJmNzAorWOWRzw/xAdSa2m0Jyr8ljQWjQeMdH78JEWrNY
laMs87H0oz0LlP+0l2rpS0vCOvY2Q6/uLzk+8l8sordDPBNC2E7gNrwjxUOIRpL3
dxRncxRbQw49tRpp6cqECCAnnyNNYNvLmEqzPnHm6KERHH5+Q/ttpUHAfj+E7QYo
3KqAF3bsiuZlRSGFE0jgW4fIKhoPNw8qZFOo40kEhIj+i6I8zEHHwK0m1uFnaZpQ
x+s9HH/aiAgkFG6hqz53P4gSVZiXn9utCeIg/o0f6k9GftiquhS9qMJvG0di2QXK
xzB7HpUuVRAdseNElQclboydaVtcrV9WJ+hgn9L0ZH/3j9y77r++C+o0mzfe8Fzg
ZMJSQqYNIH14NELBHEOhmOhIe5JJK9ljkWpwAtAbpSru5RsST8vJ5xiuZvUE2dJo
lcEx/ledUfX87UM7eb/DnYVo2JilPKK7+1sZW97wfsheR7pdiltE8URUZMDalabw
v6k/XUxyl4auHg3NIEuF4E4mTSlOlkOw/TBfUySXvDXYMUts6qf5ZPnLoBTE/FR4
E1K1Bo96wgAUlxgG77wvKjH8ESV/R+M7VOdGYni6UgcyQUidR70c9OtJEUJAnDZa
4IS9CUSRu1zRxChqaDT5LCK3/EO7xJYCznNDvt4CnOHSKkp2GdY/sA==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDP4lamZ6bo5/OU
hm75BkbPIGa1zbHH1lDqTUZE7UVl6rabLkmlJcGONvYsvI4JNQsvQ3BzB0cdeKES
6VZdq4QVFg44AbuBhy3EO9wuSuHUZhvOhyypuOOqgHV5sZjz3d9m0A3hBthsbFDw
AIAycFV73euu8mq/kz0V4SX4dc7YRtzEa+759ZM5rZBHFUv6ylv+yhspinQZKsse
TyDZdHUkoAbROu2biIfzGw+mFGfp7UcuoSVqwpcEE/SfYjjNWuetwmQsj5w9BFgS
QuUMjozOeD1gOM4G/5zqnMkPc5CyGkoWmcn+lYh7PH8Z0CYnEXj5kly09dTLsIQM
dDc9hxoLAgMBAAECggEAXfOqO6yux6ZE9MRJFSzcBbJcGSBsj6dxjGL+NhqR+by5
aKrjx8qnjpGScqeI/epGMsck5CfO4SfqjDR+vvjMSgdcx70otCKW8ZAoM5fONoMr
YAzBh7cy1ZUXArfcK6MD22B+VUwVtfLCJaXkSmdwivnCEaAn1ItD2UaXNZJwuFeF
pT9Veif4MwfRhrVvHeEK+hEsrUePOOZ7bvfvIyd2pKtBuniiaoP9LIE2E/s+G458
xFZUHDxSgumEekZLv1mt03rcNDW9B9kLELaDuVbO4mQBn3edolvmL7N2iZpPIhM/
UDMqs7HfZ70bLcENa26UAZqIenbkueg7UkZgCF5RWQKBgQDxVTizo8vF+f7BhY8o
VSvGEhyRsJsyt9wb5AkVUCSM6Q+fKTimRBoDBQijDVc20uV5HpYIy35THphmXYX8
qIYNQiaGyLwBk6YWJDfqcfCjKBm6P7vtSFWjroRj2c0GjmXBZPk4sGYj16P4Qy00
ZssPsa+ENYgc4mox6szTp5Zp1wKBgQDchLRPaz1tWoLIlIl35a5GLHZwf6GGDeDI
2bxTMhBAohbjW9NSWf7GeZgeigRd7p5s6m2EriEJwsn61W0IWUzPLJ7iTHKOrVxU
tGxHd+SV3KhOkGn1EJ8zFiNIma/nAZraGW9zH/lhq09G8ygf1y3lSCQIABG8pAbK
xHmn3BoS7QKBgQCi0hSHXqNE1v4CItILLCt0XxPXV4feGB3w01Eth/yg9T0M7QrD
Yn8KOoMxPvbwjik0JmajWGfKPIIlzkNvy2Nl3pOPrC7sAWm01orDKkxoR83T0tw/
ouXkoQHBPFkPa1NLv4xFqv2+gOanwOrmx9OIqyD32gYTNs7fDsNSqWbZ0QKBgCup
WsoewZrVQO/V+SH0J/1c8FZ17tVMCiW6dr9COlWRwlZh6AV2LCvAB46EZTjz9go6
oFSU5ZW5K6SufVgZ1ktu2kaUPFpjmNRspMPByVCiz/A+R7xt/hdvWq0VQO7MMozc
XGS+//GGqbuyiU9Em6G6Fug+m0RudanQHQZPXhpBAoGBAIuWHrYCOWJRHDw8WdOE
811QFYHpMbYc0G4/50+O/1qKADWKbqAZpnbIW8NpHrcfggkgJw6E9kmtt8HbBu/3
NuCWK1K/0aLwQQMXqgrwuNYvk1QRXbAx86fbC1XVrY2KwmuCg6snXjJZqsTI91xm
jO0LxqN3mDyK11I9/XuearPH
-----END PRIVATE KEY-----

Binary file not shown.

View File

@@ -0,0 +1,137 @@
/*
* 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.
*/
package org.apache.tomcat.util.net.openssl;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
import org.apache.tomcat.jni.SSLContext;
import org.apache.tomcat.util.net.SSLHostConfig;
import org.apache.tomcat.util.net.TesterSupport;
public class TestOpenSSLConf extends TomcatBaseTest {
private static final String ENABLED_CIPHER = "AES256-SHA256";
private static final String[] EXPECTED_CIPHERS = {ENABLED_CIPHER};
private static final String[] ENABLED_PROTOCOLS = {"TLSv1.1"};
private static final String[] DISABLED_PROTOCOLS = {"SSLv3", "TLSv1", "TLSv1.2"};
private static final String[] DISABLED_PROTOCOLS_TLS13 = {"TLSv1.3"};
// Test behavior needs to adjust for OpenSSL 1.1.1-pre3 and above
private static final int OPENSSL_TLS13_SUPPORT_MIN_VERSION = 0x10101003;
private static int OPENSSL_VERSION = TesterSupport.getOpensslVersion();
private static boolean hasTLS13() {
return OPENSSL_VERSION >= OPENSSL_TLS13_SUPPORT_MIN_VERSION;
}
public SSLHostConfig initOpenSSLConfCmd(String... commands) throws Exception {
Assert.assertNotNull(commands);
Assert.assertTrue("Invalid length", commands.length % 2 == 0);
Tomcat tomcat = getTomcatInstance();
TesterSupport.initSsl(tomcat);
String protocol = tomcat.getConnector().getProtocolHandlerClassName();
// The tests are only supported for APR and OpenSSL
if (!protocol.contains("Apr")) {
String sslImplementation = String.valueOf(
tomcat.getConnector().getProperty("sslImplementationName"));
Assume.assumeTrue("This test is only for OpenSSL based SSL connectors",
sslImplementation.contains("openssl"));
}
OpenSSLConf conf = new OpenSSLConf();
for (int i = 0; i < commands.length;) {
OpenSSLConfCmd cmd = new OpenSSLConfCmd();
cmd.setName(commands[i++]);
cmd.setValue(commands[i++]);
conf.addCmd(cmd);
}
SSLHostConfig[] sslHostConfigs = tomcat.getConnector().
getProtocolHandler().findSslHostConfigs();
Assert.assertEquals("Wrong SSLHostConfigCount", 1, sslHostConfigs.length);
sslHostConfigs[0].setOpenSslConf(conf);
tomcat.start();
sslHostConfigs = tomcat.getConnector().getProtocolHandler().findSslHostConfigs();
Assert.assertEquals("Wrong SSLHostConfigCount", 1, sslHostConfigs.length);
return sslHostConfigs[0];
}
@Test
public void testOpenSSLConfCmdCipher() throws Exception {
log.info("Found OpenSSL version 0x" + Integer.toHexString(OPENSSL_VERSION));
SSLHostConfig sslHostConfig;
if (hasTLS13()) {
// Ensure TLSv1.3 ciphers aren't returned
sslHostConfig = initOpenSSLConfCmd("CipherString", ENABLED_CIPHER,
"CipherSuites", "");
} else {
sslHostConfig = initOpenSSLConfCmd("CipherString", ENABLED_CIPHER);
}
String[] ciphers = sslHostConfig.getEnabledCiphers();
Assert.assertThat("Wrong HostConfig ciphers", ciphers,
CoreMatchers.is(EXPECTED_CIPHERS));
ciphers = SSLContext.getCiphers(sslHostConfig.getOpenSslContext().longValue());
Assert.assertThat("Wrong native SSL context ciphers", ciphers,
CoreMatchers.is(EXPECTED_CIPHERS));
}
@Test
public void testOpenSSLConfCmdProtocol() throws Exception {
log.info("Found OpenSSL version 0x" + Integer.toHexString(OPENSSL_VERSION));
Set<String> disabledProtocols = new HashSet<>(Arrays.asList(DISABLED_PROTOCOLS));
StringBuilder sb = new StringBuilder();
for (String protocol : DISABLED_PROTOCOLS) {
sb.append(",").append("-").append(protocol);
}
if (hasTLS13()) {
// Also disable TLSv1.3
for (String protocol : DISABLED_PROTOCOLS_TLS13) {
sb.append(",").append("-").append(protocol);
disabledProtocols.add(protocol);
}
}
for (String protocol : ENABLED_PROTOCOLS) {
sb.append(",").append(protocol);
}
SSLHostConfig sslHostConfig = initOpenSSLConfCmd("Protocol", sb.substring(1));
String[] protocols = sslHostConfig.getEnabledProtocols();
for (String protocol : protocols) {
Assert.assertFalse("Protocol " + protocol + " is not allowed",
disabledProtocols.contains(protocol));
}
Set<String> enabledProtocols = new HashSet<>(Arrays.asList(protocols));
for (String protocol : ENABLED_PROTOCOLS) {
Assert.assertTrue("Protocol " + protocol + " is not enabled",
enabledProtocols.contains(protocol));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,620 @@
/*
* 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.
*/
package org.apache.tomcat.util.net.openssl.ciphers;
import java.util.List;
import java.util.TreeSet;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
public class TestOpenSSLCipherConfigurationParser {
@Test
public void testDEFAULT() throws Exception {
if (TesterOpenSSL.VERSION < 10100) {
// Account for classes of ciphers removed from DEFAULT in 1.1.0
testSpecification("DEFAULT:!RC4:!DSS:!SEED:!IDEA:!CAMELLIA:!AESCCM:!3DES");
} else {
testSpecification("DEFAULT");
}
}
@Test
public void testCOMPLEMENTOFDEFAULT() throws Exception {
if (TesterOpenSSL.VERSION < 10100) {
// Account for classes of ciphers removed from DEFAULT in 1.1.0
testSpecification("COMPLEMENTOFDEFAULT:RC4:DSS:SEED:IDEA:CAMELLIA:AESCCM:aNULL:3DES");
} else {
testSpecification("COMPLEMENTOFDEFAULT");
}
}
@Test
public void testALL() throws Exception {
testSpecification("ALL");
}
@Test
public void testCOMPLEMENTOFALL() throws Exception {
testSpecification("COMPLEMENTOFALL");
}
@Test
public void testaNULL() throws Exception {
testSpecification("aNULL");
}
@Test
public void testeNULL() throws Exception {
testSpecification("eNULL");
}
@Test
public void testHIGH() throws Exception {
testSpecification("HIGH");
}
@Test
public void testMEDIUM() throws Exception {
testSpecification("MEDIUM");
}
@Test
public void testLOW() throws Exception {
testSpecification("LOW");
}
@Test
public void testEXPORT40() throws Exception {
testSpecification("EXPORT40");
}
@Test
public void testEXPORT() throws Exception {
testSpecification("EXPORT");
}
@Test
public void testRSA() throws Exception {
testSpecification("RSA");
}
@Test
public void testaRSA() throws Exception {
testSpecification("aRSA");
}
@Test
public void testkRSA() throws Exception {
testSpecification("kRSA");
}
@Test
public void testkEDH() throws Exception {
testSpecification("kEDH");
}
@Test
public void testkDHE() throws Exception {
// This alias was introduced in 1.0.2
if (TesterOpenSSL.VERSION >= 10002) {
testSpecification("kDHE");
}
}
@Test
public void testEDH() throws Exception {
testSpecification("EDH");
}
@Test
public void testDHE() throws Exception {
// This alias was introduced in 1.0.2
if (TesterOpenSSL.VERSION >= 10002) {
testSpecification("DHE");
}
}
@Test
public void testkDHr() throws Exception {
testSpecification("kDHr");
}
@Test
public void testkDHd() throws Exception {
testSpecification("kDHd");
}
@Test
public void testkDH() throws Exception {
testSpecification("kDH");
}
@Test
public void testkECDHr() throws Exception {
testSpecification("kECDHr");
}
@Test
public void testkECDHe() throws Exception {
testSpecification("kECDHe");
}
@Test
public void testkECDH() throws Exception {
testSpecification("kECDH");
}
@Test
public void testkEECDH() throws Exception {
testSpecification("kEECDH");
}
@Test
public void testECDH() throws Exception {
testSpecification("ECDH");
}
@Test
public void testkECDHE() throws Exception {
testSpecification("kECDHE");
}
@Test
public void testECDHE() throws Exception {
testSpecification("ECDHE");
}
@Test
@Ignore("Contrary to the docs, OpenSSL does not recognise EECDHE")
public void testEECDHE() throws Exception {
testSpecification("EECDHE");
}
@Test
public void testAECDH() throws Exception {
testSpecification("AECDH");
}
@Test
public void testDSS() throws Exception {
testSpecification("DSS");
}
@Test
public void testaDSS() throws Exception {
testSpecification("aDSS");
}
@Test
public void testaDH() throws Exception {
testSpecification("aDH");
}
@Test
public void testaECDH() throws Exception {
testSpecification("aECDH");
}
@Test
public void testaECDSA() throws Exception {
testSpecification("aECDSA");
}
@Test
public void testECDSA() throws Exception {
testSpecification("ECDSA");
}
@Test
public void testkFZA() throws Exception {
testSpecification("kFZA");
}
@Test
public void testaFZA() throws Exception {
testSpecification("aFZA");
}
@Test
public void testeFZA() throws Exception {
testSpecification("eFZA");
}
@Test
public void testFZA() throws Exception {
testSpecification("FZA");
}
@Test
public void testTLSv1_2() throws Exception {
testSpecification("TLSv1.2");
}
@Test
public void testTLSv1() throws Exception {
// In OpenSSL 1.1.0-dev, TLSv1 refers to those ciphers that require
// TLSv1 rather than being an alias for SSLv3
if (TesterOpenSSL.VERSION >= 10100) {
testSpecification("TLSv1");
}
}
@Test
public void testSSLv2() throws Exception {
testSpecification("SSLv2");
}
@Test
public void testSSLv3() throws Exception {
// In OpenSSL 1.1.0-dev, TLSv1 refers to those ciphers that require
// TLSv1 rather than being an alias for SSLv3
if (TesterOpenSSL.VERSION < 10100) {
testSpecification("SSLv3:TLSv1");
}
}
@Test
public void testDH() throws Exception {
testSpecification("DH");
}
@Test
public void testADH() throws Exception {
testSpecification("ADH");
}
@Test
public void testAES128() throws Exception {
testSpecification("AES128");
}
@Test
public void testAES256() throws Exception {
testSpecification("AES256");
}
@Test
public void testAES() throws Exception {
testSpecification("AES");
}
@Test
public void testAESGCM() throws Exception {
testSpecification("AESGCM");
}
@Test
public void testAESCCM() throws Exception {
testSpecification("AESCCM");
}
@Test
public void testAESCCM8() throws Exception {
testSpecification("AESCCM8");
}
@Test
public void testCAMELLIA128() throws Exception {
testSpecification("CAMELLIA128");
}
@Test
public void testCAMELLIA256() throws Exception {
testSpecification("CAMELLIA256");
}
@Test
public void testCAMELLIA() throws Exception {
testSpecification("CAMELLIA");
}
@Test
public void testCHACHA20() throws Exception {
testSpecification("CHACHA20");
}
@Test
public void test3DES() throws Exception {
testSpecification("3DES");
}
@Test
public void testDES() throws Exception {
testSpecification("DES");
}
@Test
public void testRC4() throws Exception {
testSpecification("RC4");
}
@Test
public void testRC2() throws Exception {
testSpecification("RC2");
}
@Test
public void testIDEA() throws Exception {
testSpecification("IDEA");
}
@Test
public void testSEED() throws Exception {
testSpecification("SEED");
}
@Test
public void testMD5() throws Exception {
testSpecification("MD5");
}
@Test
public void testSHA1() throws Exception {
testSpecification("SHA1");
}
@Test
public void testSHA() throws Exception {
testSpecification("SHA");
}
@Test
public void testSHA256() throws Exception {
testSpecification("SHA256");
}
@Test
public void testSHA384() throws Exception {
testSpecification("SHA384");
}
@Test
public void testKRB5() throws Exception {
testSpecification("KRB5");
}
@Test
public void testaGOST() throws Exception {
testSpecification("aGOST");
}
@Test
public void testaGOST01() throws Exception {
testSpecification("aGOST01");
}
@Test
public void testaGOST94() throws Exception {
testSpecification("aGOST94");
}
@Test
public void testkGOST() throws Exception {
testSpecification("kGOST");
}
@Test
public void testGOST94() throws Exception {
testSpecification("GOST94");
}
@Test
public void testGOST89MAC() throws Exception {
testSpecification("GOST89MAC");
}
@Test
public void testaPSK() throws Exception {
testSpecification("aPSK");
}
@Test
public void testkPSK() throws Exception {
testSpecification("kPSK");
}
@Test
public void testkRSAPSK() throws Exception {
testSpecification("kRSAPSK");
}
@Test
public void testkECDHEPSK() throws Exception {
testSpecification("kECDHEPSK");
}
@Test
public void testkDHEPSK() throws Exception {
testSpecification("kDHEPSK");
}
@Test
public void testPSK() throws Exception {
testSpecification("PSK");
}
@Test
public void testARIA() throws Exception {
testSpecification("ARIA");
}
@Test
public void testARIA128() throws Exception {
testSpecification("ARIA128");
}
@Test
public void testARIA256() throws Exception {
testSpecification("ARIA256");
}
// TODO: Add tests for the individual operators
@Test
public void testSpecification01() throws Exception {
// Tomcat 8 default as of 2014-08-04
// This gets an A- from https://www.ssllabs.com/ssltest with no FS for
// a number of the reference browsers
testSpecification("HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5");
}
@Test
public void testSpecification02() throws Exception {
// Suggestion from dev list (s/ECDHE/kEECDH/, s/DHE/EDH/
testSpecification("!aNULL:!eNULL:!EXPORT:!DSS:!DES:!SSLv2:kEECDH:ECDH:EDH:AES256-GCM-SHA384:AES128-GCM-SHA256:+RC4:HIGH:aRSA:kECDHr:MEDIUM");
}
@Test
public void testSpecification03() throws Exception {
// Reported as failing during 8.0.11 release vote by Ognjen Blagojevic
// EDH was introduced in 1.0.0
testSpecification("EECDH+aRSA+SHA384:EECDH:EDH+aRSA:RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS");
}
private void testSpecification(String specification) throws Exception {
// Filter out cipher suites that OpenSSL does not implement
String openSSLCipherList = TesterOpenSSL.getOpenSSLCiphersAsExpression(specification);
List<String> jsseCipherListFromOpenSSL =
OpenSSLCipherConfigurationParser.parseExpression(openSSLCipherList);
List<String> jsseCipherListFromParser =
OpenSSLCipherConfigurationParser.parseExpression(specification);
TesterOpenSSL.removeUnimplementedCiphersJsse(jsseCipherListFromParser);
// First check the lists have the same entries
// Order is NOT important at this point. It is checked below.
Assert.assertEquals(
"Expected " + jsseCipherListFromParser.size() + " ciphers but got "
+ jsseCipherListFromOpenSSL.size() + " for the specification '"
+ specification + "'",
new TreeSet<>(jsseCipherListFromParser), new TreeSet<>(jsseCipherListFromOpenSSL));
// OpenSSL treats many ciphers as having equal preference. The order
// returned depends on the order they are requested. The following code
// checks that the Parser produces a cipher list that is consistent with
// OpenSSL's preference order by confirming that running through OpenSSL
// does not change the order.
String parserOrderedExpression = listToString(jsseCipherListFromParser, ',');
Assert.assertEquals(
listToString(OpenSSLCipherConfigurationParser.parseExpression(
parserOrderedExpression), ','),
parserOrderedExpression);
}
private String listToString(List<String> list, char separator) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (String entry : list) {
if (first) {
first = false;
} else {
sb.append(separator);
}
sb.append(entry);
}
return sb.toString();
}
}

View File

@@ -0,0 +1,113 @@
/*
* 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.
*/
package org.apache.tomcat.util.net.openssl.ciphers;
import java.util.LinkedHashSet;
import org.junit.Assert;
import org.junit.Test;
/*
* The unit test is independent of OpenSSL version and does not require OpenSSL
* to be present.
*/
public class TestOpenSSLCipherConfigurationParserOnly {
@Test
public void testDefaultSort01() throws Exception {
// Reproducing a failure observed on Gump with OpenSSL 1.1.x
// Everything else being equal, AES is preferred
LinkedHashSet<Cipher> input = new LinkedHashSet<>();
input.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384);
input.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
input.add(Cipher.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
input.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384);
LinkedHashSet<Cipher> result = OpenSSLCipherConfigurationParser.defaultSort(input);
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
expected.add(Cipher.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
expected.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384);
expected.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384);
expected.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
Assert.assertEquals(expected.toString(), result.toString());
}
@Test
public void testDefaultSort02() throws Exception {
// Reproducing a failure observed on Gump with OpenSSL 1.1.x
// ECHDE should beat AES
LinkedHashSet<Cipher> input = new LinkedHashSet<>();
input.add(Cipher.TLS_RSA_WITH_AES_256_CBC_SHA);
input.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384);
LinkedHashSet<Cipher> result = OpenSSLCipherConfigurationParser.defaultSort(input);
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
expected.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384);
expected.add(Cipher.TLS_RSA_WITH_AES_256_CBC_SHA);
Assert.assertEquals(expected.toString(), result.toString());
}
@Test
public void testDefaultSort03() throws Exception {
// Reproducing a failure observed on Gump with OpenSSL 1.1.x
// AES should beat CAMELLIA
LinkedHashSet<Cipher> input = new LinkedHashSet<>();
input.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
input.add(Cipher.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384);
LinkedHashSet<Cipher> result = OpenSSLCipherConfigurationParser.defaultSort(input);
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
expected.add(Cipher.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384);
expected.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
Assert.assertEquals(expected.toString(), result.toString());
}
@Test
public void testRename01() throws Exception {
// EDH -> DHE
LinkedHashSet<Cipher> result =
OpenSSLCipherConfigurationParser.parse("EXP-EDH-DSS-DES-CBC-SHA");
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
expected.add(Cipher.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA);
Assert.assertEquals(expected, result);
}
@Test
public void testCustomOrdering() throws Exception {
// https://bz.apache.org/bugzilla/show_bug.cgi?id=59081
LinkedHashSet<Cipher> result = OpenSSLCipherConfigurationParser.parse(
"ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:" +
"DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DES-CBC3-SHA");
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
expected.add(Cipher.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
expected.add(Cipher.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA);
expected.add(Cipher.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA);
expected.add(Cipher.TLS_DHE_RSA_WITH_AES_256_CBC_SHA);
expected.add(Cipher.TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
expected.add(Cipher.TLS_RSA_WITH_3DES_EDE_CBC_SHA);
Assert.assertEquals(expected.toString(), result.toString());
}
}

View File

@@ -0,0 +1,527 @@
/*
* 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.
*/
package org.apache.tomcat.util.net.openssl.ciphers;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.catalina.util.IOTools;
public class TesterOpenSSL {
public static final int VERSION;
public static final Set<Cipher> OPENSSL_UNIMPLEMENTED_CIPHERS;
public static final Map<String,String> OPENSSL_RENAMED_CIPHERS;
static {
// Note: The following lists are intended to be aligned with the most
// recent release of each OpenSSL release branch. Running the unit
// tests with earlier releases is likely to result in failures.
String versionString = null;
try {
versionString = executeOpenSSLCommand("version");
} catch (IOException e) {
versionString = "";
}
if (versionString.startsWith("OpenSSL 3.0.0")) {
// Note: Gump currently tests 9.0.x with OpenSSL master
// (a.k.a 3.0.0-dev)
VERSION = 30000;
} else if (versionString.startsWith("OpenSSL 1.1.1")) {
// LTS
// Supported until at least 2023-09-11
VERSION = 10101;
} else if (versionString.startsWith("OpenSSL 1.1.0")) {
// Support ends 2019-09-11
VERSION = 10100;
} else if (versionString.startsWith("OpenSSL 1.0.2")) {
// LTS
// Support ends 2019-12-31
// Note: Gump current tests 8.5.x with OpenSSL 1.0.2
VERSION = 10002;
// Note: Release branches 1.0.1 and earlier are no longer supported by
// the OpenSSL team so these tests don't support them either.
} else {
VERSION = -1;
}
HashSet<Cipher> unimplemented = new HashSet<>();
// These have been removed from all supported versions.
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_RC4_128_SHA);
unimplemented.add(Cipher.TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA);
unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA);
unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5);
unimplemented.add(Cipher.TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA);
unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC4_56_SHA);
unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC4_56_MD5);
unimplemented.add(Cipher.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256);
unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256);
unimplemented.add(Cipher.TLS_DH_anon_WITH_DES_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_anon_EXPORT_WITH_RC4_40_MD5);
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_DES_CBC_SHA);
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_DES_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_RSA_WITH_DES_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_DSS_WITH_DES_CBC_SHA);
unimplemented.add(Cipher.TLS_RSA_WITH_DES_CBC_SHA);
unimplemented.add(Cipher.SSL2_DES_64_CBC_WITH_MD5);
unimplemented.add(Cipher.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA);
unimplemented.add(Cipher.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA);
unimplemented.add(Cipher.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA);
unimplemented.add(Cipher.TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5);
unimplemented.add(Cipher.TLS_RSA_EXPORT_WITH_RC4_40_MD5);
unimplemented.add(Cipher.SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5);
unimplemented.add(Cipher.SSL_CK_RC2_128_CBC_WITH_MD5);
unimplemented.add(Cipher.SSL_CK_RC4_128_WITH_MD5);
unimplemented.add(Cipher.SSL2_RC4_128_EXPORT40_WITH_MD5);
unimplemented.add(Cipher.SSL2_IDEA_128_CBC_WITH_MD5);
unimplemented.add(Cipher.SSL2_DES_192_EDE3_CBC_WITH_MD5);
// These are TLS v1.3 cipher suites
// Java does not currently support these so they are excluded from the
// testing.
// Note: If OpenSSL is used then some of these may be available
// depending on the OpenSSL version used and the defaults for that
// version
unimplemented.add(Cipher.TLS_AES_128_CCM_8_SHA256);
unimplemented.add(Cipher.TLS_AES_128_CCM_SHA256);
unimplemented.add(Cipher.TLS_AES_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_AES_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_CHACHA20_POLY1305_SHA256);
if (VERSION < 10100) {
// These were implemented in 1.1.0 so won't be available in any
// earlier version
unimplemented.add(Cipher.TLS_PSK_WITH_NULL_SHA);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_NULL_SHA);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_NULL_SHA);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_PSK_WITH_NULL_SHA256);
unimplemented.add(Cipher.TLS_PSK_WITH_NULL_SHA384);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_NULL_SHA256);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_NULL_SHA384);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_NULL_SHA256);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_NULL_SHA384);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_RC4_128_SHA);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_CBC_SHA);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_CBC_SHA);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_RC4_128_SHA);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_128_CBC_SHA);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_256_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_RC4_128_SHA);
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_NULL_SHA);
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_NULL_SHA256);
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_NULL_SHA384);
unimplemented.add(Cipher.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256);
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256);
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256);
unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256);
unimplemented.add(Cipher.TLS_RSA_WITH_AES_128_CCM);
unimplemented.add(Cipher.TLS_RSA_WITH_AES_256_CCM);
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_AES_128_CCM);
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_AES_256_CCM);
unimplemented.add(Cipher.TLS_RSA_WITH_AES_128_CCM_8);
unimplemented.add(Cipher.TLS_RSA_WITH_AES_256_CCM_8);
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_AES_128_CCM_8);
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_AES_256_CCM_8);
unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_CCM);
unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_CCM);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_CCM);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_CCM);
unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_CCM_8);
unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_CCM_8);
unimplemented.add(Cipher.TLS_PSK_DHE_WITH_AES_128_CCM_8);
unimplemented.add(Cipher.TLS_PSK_DHE_WITH_AES_256_CCM_8);
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_128_CCM);
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_256_CCM);
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8);
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8);
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256);
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
unimplemented.add(Cipher.TLS_PSK_WITH_CHACHA20_POLY1305_SHA256);
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256);
} else {
// These were removed in 1.1.0 so won't be available from that
// version onwards.
unimplemented.add(Cipher.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_128_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_256_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_256_CBC_SHA256);
unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_DSS_WITH_SEED_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_128_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_256_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_256_CBC_SHA256);
unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_RSA_WITH_SEED_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_NULL_SHA);
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_RC4_128_SHA);
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_RC4_128_SHA);
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_NULL_SHA);
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_RC4_128_SHA);
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256);
unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384);
unimplemented.add(Cipher.TLS_RSA_WITH_RC4_128_MD5);
unimplemented.add(Cipher.TLS_DH_anon_WITH_RC4_128_MD5);
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_RC4_128_SHA);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_RC4_128_SHA);
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_RC4_128_SHA);
unimplemented.add(Cipher.TLS_RSA_WITH_RC4_128_SHA);
unimplemented.add(Cipher.TLS_PSK_WITH_RC4_128_SHA);
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_RC4_128_SHA);
unimplemented.add(Cipher.TLS_ECDH_anon_WITH_RC4_128_SHA);
// 3DES requires a compile time switch to enable. Treat as removed.
unimplemented.add(Cipher.TLS_PSK_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_RSA_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA);
unimplemented.add(Cipher.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA);
}
if (VERSION < 10101) {
// These were implemented in 1.1.1 so won't be available in any
// earlier version
unimplemented.add(Cipher.TLS_RSA_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_RSA_WITH_ARIA_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_PSK_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_PSK_WITH_ARIA_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384);
}
String skipCiphers = System.getProperty("tomcat.test.openssl.unimplemented", "");
if (!skipCiphers.isEmpty()) {
String[] skip = skipCiphers.split(",");
for (Cipher c : Cipher.values()) {
for (String s : skip) {
if (c.toString().contains(s)) {
unimplemented.add(c);
}
}
}
}
OPENSSL_UNIMPLEMENTED_CIPHERS = Collections.unmodifiableSet(unimplemented);
Map<String,String> renamed = new HashMap<>();
renamed.put("ECDH-ECDSA-RC4-SHA+SSLv3", "ECDH-ECDSA-RC4-SHA+TLSv1");
renamed.put("ECDHE-ECDSA-NULL-SHA+SSLv3", "ECDHE-ECDSA-NULL-SHA+TLSv1");
renamed.put("ECDHE-ECDSA-DES-CBC3-SHA+SSLv3", "ECDHE-ECDSA-DES-CBC3-SHA+TLSv1");
renamed.put("ECDHE-ECDSA-AES128-SHA+SSLv3", "ECDHE-ECDSA-AES128-SHA+TLSv1");
renamed.put("ECDHE-ECDSA-AES256-SHA+SSLv3", "ECDHE-ECDSA-AES256-SHA+TLSv1");
renamed.put("ECDHE-RSA-NULL-SHA+SSLv3", "ECDHE-RSA-NULL-SHA+TLSv1");
renamed.put("ECDHE-RSA-RC4-SHA+SSLv3", "ECDHE-RSA-RC4-SHA+TLSv1");
renamed.put("ECDHE-RSA-DES-CBC3-SHA+SSLv3", "ECDHE-RSA-DES-CBC3-SHA+TLSv1");
renamed.put("ECDHE-RSA-AES128-SHA+SSLv3", "ECDHE-RSA-AES128-SHA+TLSv1");
renamed.put("ECDHE-RSA-AES256-SHA+SSLv3", "ECDHE-RSA-AES256-SHA+TLSv1");
renamed.put("AECDH-NULL-SHA+SSLv3", "AECDH-NULL-SHA+TLSv1");
renamed.put("AECDH-RC4-SHA+SSLv3", "AECDH-RC4-SHA+TLSv1");
renamed.put("AECDH-DES-CBC3-SHA+SSLv3", "AECDH-DES-CBC3-SHA+TLSv1");
renamed.put("AECDH-AES128-SHA+SSLv3", "AECDH-AES128-SHA+TLSv1");
renamed.put("AECDH-AES256-SHA+SSLv3", "AECDH-AES256-SHA+TLSv1");
renamed.put("ECDHE-PSK-RC4-SHA+SSLv3", "ECDHE-PSK-RC4-SHA+TLSv1");
renamed.put("ECDHE-PSK-3DES-EDE-CBC-SHA+SSLv3", "ECDHE-PSK-3DES-EDE-CBC-SHA+TLSv1");
renamed.put("ECDHE-PSK-AES128-CBC-SHA+SSLv3", "ECDHE-PSK-AES128-CBC-SHA+TLSv1");
renamed.put("ECDHE-PSK-AES256-CBC-SHA+SSLv3", "ECDHE-PSK-AES256-CBC-SHA+TLSv1");
renamed.put("ECDHE-PSK-NULL-SHA+SSLv3", "ECDHE-PSK-NULL-SHA+TLSv1");
OPENSSL_RENAMED_CIPHERS = Collections.unmodifiableMap(renamed);
}
private TesterOpenSSL() {
// Utility class. Hide default constructor.
}
public static Set<String> getOpenSSLCiphersAsSet(String specification) throws Exception {
String[] ciphers = getOpenSSLCiphersAsExpression(specification).trim().split(":");
Set<String> result = new HashSet<>(ciphers.length);
for (String cipher : ciphers) {
result.add(cipher);
}
return result;
}
public static String getOpenSSLCiphersAsExpression(String specification) throws Exception {
List<String> args = new ArrayList<>();
// Standard command to list the ciphers
args.add("ciphers");
args.add("-v");
if (VERSION < 10100) {
// Need to exclude the GOST ciphers
if (specification == null) {
specification = "DEFAULT:!aGOST";
} else {
specification = "!aGOST:" + specification;
}
}
if (VERSION >= 10101) {
// Need to exclude the TLSv1.3 ciphers
args.add("-ciphersuites");
args.add("");
}
// Include the specification if provided
if (specification != null) {
args.add(specification);
}
String stdout = executeOpenSSLCommand(args.toArray(new String[args.size()]));
if (stdout.length() == 0) {
return stdout;
}
StringBuilder output = new StringBuilder();
boolean first = true;
// OpenSSL should have returned one cipher per line
String ciphers[] = stdout.split("\n");
for (String cipher : ciphers) {
// Handle rename for 1.1.0 onwards
cipher = cipher.replaceAll("EDH", "DHE");
if (first) {
first = false;
} else {
output.append(':');
}
StringBuilder name = new StringBuilder();
// Name is first part
int i = cipher.indexOf(' ');
name.append(cipher.substring(0, i));
// Advance i past the space
while (Character.isWhitespace(cipher.charAt(i))) {
i++;
}
// Protocol is the second
int j = cipher.indexOf(' ', i);
name.append('+');
name.append(cipher.substring(i, j));
// More renames
if (OPENSSL_RENAMED_CIPHERS.containsKey(name.toString())) {
output.append(OPENSSL_RENAMED_CIPHERS.get(name.toString()));
} else {
output.append(name.toString());
}
}
return output.toString();
}
/*
* Use this method to filter parser results when comparing them to OpenSSL
* results to take account of unimplemented cipher suites.
*/
public static void removeUnimplementedCiphersJsse(List<String> list) {
for (Cipher cipher : OPENSSL_UNIMPLEMENTED_CIPHERS) {
for (String jsseName : cipher.getJsseNames()) {
list.remove(jsseName);
}
}
}
private static String executeOpenSSLCommand(String... args) throws IOException {
String openSSLPath = System.getProperty("tomcat.test.openssl.path");
String openSSLLibPath = null;
if (openSSLPath == null || openSSLPath.length() == 0) {
openSSLPath = "openssl";
} else {
// Explicit OpenSSL path may also need explicit lib path
// (e.g. Gump needs this)
openSSLLibPath = openSSLPath.substring(0, openSSLPath.lastIndexOf('/'));
openSSLLibPath = openSSLLibPath + "/../lib";
}
List<String> cmd = new ArrayList<>();
cmd.add(openSSLPath);
for (String arg : args) {
cmd.add(arg);
}
ProcessBuilder pb = new ProcessBuilder(cmd.toArray(new String[cmd.size()]));
if (openSSLLibPath != null) {
Map<String,String> env = pb.environment();
String libraryPath = env.get("LD_LIBRARY_PATH");
if (libraryPath == null) {
libraryPath = openSSLLibPath;
} else {
libraryPath = libraryPath + ":" + openSSLLibPath;
}
env.put("LD_LIBRARY_PATH", libraryPath);
}
Process p = pb.start();
InputStreamToText stdout = new InputStreamToText(p.getInputStream());
InputStreamToText stderr = new InputStreamToText(p.getErrorStream());
Thread t1 = new Thread(stdout);
t1.setName("OpenSSL stdout reader");
t1.start();
Thread t2 = new Thread(stderr);
t2.setName("OpenSSL stderr reader");
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
throw new IOException(e);
}
String errorText = stderr.getText();
if (errorText.length() > 0) {
System.err.println(errorText);
}
return stdout.getText().trim();
}
private static class InputStreamToText implements Runnable {
private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
private final InputStream is;
InputStreamToText(InputStream is) {
this.is = is;
}
@Override
public void run() {
try {
IOTools.flow(is, baos);
} catch (IOException e) {
// Ignore
}
}
public String getText() {
return baos.toString();
}
}
}

Binary file not shown.