350 lines
12 KiB
Java
350 lines
12 KiB
Java
/*
|
|
* 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();
|
|
}
|
|
}
|