init
This commit is contained in:
141
test/org/apache/tomcat/util/net/IPv6UtilsTest.java
Normal file
141
test/org/apache/tomcat/util/net/IPv6UtilsTest.java
Normal 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"));
|
||||
}
|
||||
}
|
||||
182
test/org/apache/tomcat/util/net/TestClientCert.java
Normal file
182
test/org/apache/tomcat/util/net/TestClientCert.java
Normal 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();
|
||||
}
|
||||
}
|
||||
84
test/org/apache/tomcat/util/net/TestClientCertTls13.java
Normal file
84
test/org/apache/tomcat/util/net/TestClientCertTls13.java
Normal 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();
|
||||
}
|
||||
}
|
||||
184
test/org/apache/tomcat/util/net/TestCustomSsl.java
Normal file
184
test/org/apache/tomcat/util/net/TestCustomSsl.java
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
112
test/org/apache/tomcat/util/net/TestSSLHostConfig.java
Normal file
112
test/org/apache/tomcat/util/net/TestSSLHostConfig.java
Normal 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());
|
||||
}
|
||||
}
|
||||
349
test/org/apache/tomcat/util/net/TestSSLHostConfigCompat.java
Normal file
349
test/org/apache/tomcat/util/net/TestSSLHostConfigCompat.java
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
198
test/org/apache/tomcat/util/net/TestSsl.java
Normal file
198
test/org/apache/tomcat/util/net/TestSsl.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
198
test/org/apache/tomcat/util/net/TestXxxEndpoint.java
Normal file
198
test/org/apache/tomcat/util/net/TestXxxEndpoint.java
Normal 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();
|
||||
}
|
||||
}
|
||||
698
test/org/apache/tomcat/util/net/TesterSupport.java
Normal file
698
test/org/apache/tomcat/util/net/TesterSupport.java
Normal 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));
|
||||
}
|
||||
}
|
||||
38
test/org/apache/tomcat/util/net/ca-cert.pem
Normal file
38
test/org/apache/tomcat/util/net/ca-cert.pem
Normal 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-----
|
||||
BIN
test/org/apache/tomcat/util/net/ca.jks
Normal file
BIN
test/org/apache/tomcat/util/net/ca.jks
Normal file
Binary file not shown.
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
test/org/apache/tomcat/util/net/keystore-info.txt
Normal file
28
test/org/apache/tomcat/util/net/keystore-info.txt
Normal 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
|
||||
86
test/org/apache/tomcat/util/net/localhost-ec-cert.pem
Normal file
86
test/org/apache/tomcat/util/net/localhost-ec-cert.pem
Normal 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-----
|
||||
5
test/org/apache/tomcat/util/net/localhost-ec-key.pem
Normal file
5
test/org/apache/tomcat/util/net/localhost-ec-key.pem
Normal file
@@ -0,0 +1,5 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg0U7ZRpeTEzVDXCCP
|
||||
oKwgWnN0tf7CMaE9dJmLIPpNgnChRANCAAQQzCS3DCr+pq/qstwm8YEGrgvr8MBf
|
||||
o+5a49N8ArBYbEcObgisMOF25ZwGgK9CzqdvSbXslQixqeN694RP4gVg
|
||||
-----END PRIVATE KEY-----
|
||||
BIN
test/org/apache/tomcat/util/net/localhost-ec.jks
Normal file
BIN
test/org/apache/tomcat/util/net/localhost-ec.jks
Normal file
Binary file not shown.
109
test/org/apache/tomcat/util/net/localhost-rsa-cert.pem
Normal file
109
test/org/apache/tomcat/util/net/localhost-rsa-cert.pem
Normal 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-----
|
||||
BIN
test/org/apache/tomcat/util/net/localhost-rsa-copy1.jks
Normal file
BIN
test/org/apache/tomcat/util/net/localhost-rsa-copy1.jks
Normal file
Binary file not shown.
28
test/org/apache/tomcat/util/net/localhost-rsa-key.pem
Normal file
28
test/org/apache/tomcat/util/net/localhost-rsa-key.pem
Normal 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-----
|
||||
BIN
test/org/apache/tomcat/util/net/localhost-rsa.jks
Normal file
BIN
test/org/apache/tomcat/util/net/localhost-rsa.jks
Normal file
Binary file not shown.
137
test/org/apache/tomcat/util/net/openssl/TestOpenSSLConf.java
Normal file
137
test/org/apache/tomcat/util/net/openssl/TestOpenSSLConf.java
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
1117
test/org/apache/tomcat/util/net/openssl/ciphers/TestCipher.java
Normal file
1117
test/org/apache/tomcat/util/net/openssl/ciphers/TestCipher.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
test/org/apache/tomcat/util/net/user1.jks
Normal file
BIN
test/org/apache/tomcat/util/net/user1.jks
Normal file
Binary file not shown.
Reference in New Issue
Block a user