diff --git a/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/pom.xml b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/pom.xml new file mode 100644 index 000000000000..955c5218fb4d --- /dev/null +++ b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/pom.xml @@ -0,0 +1,62 @@ + + + + 4.0.0 + + + org.eclipse.jetty + jetty-alpn + 12.0.16-SNAPSHOT + + jetty-alpn-bouncycastle-client + Core :: ALPN :: Bouncy Castle Client + + + ${project.groupId}.alpn.bouncycastle.client + + + + + org.bouncycastle + bctls-fips + + + org.eclipse.jetty + jetty-alpn-client + + + org.slf4j + slf4j-api + + + org.eclipse.jetty + jetty-slf4j-impl + test + + + org.eclipse.jetty.http2 + jetty-http2-client + test + + + + + + org.apache.felix + maven-bundle-plugin + true + + + Bouncy Castle Client ALPN + ${osgi.slf4j.import.packages},org.bouncycastle;version="${bouncycastle.version}",* + * + osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional + osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client + <_nouses>true + + + + + + + diff --git a/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/main/java/module-info.java b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/main/java/module-info.java new file mode 100644 index 000000000000..910ab12cacf5 --- /dev/null +++ b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/main/java/module-info.java @@ -0,0 +1,23 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +module org.eclipse.jetty.alpn.bouncycastle.client +{ + requires org.slf4j; + + requires transitive org.eclipse.jetty.alpn.client; + requires org.bouncycastle.fips.tls; + + provides org.eclipse.jetty.io.ssl.ALPNProcessor.Client with + org.eclipse.jetty.alpn.bouncycastle.client.BouncycastleClientALPNProcessor; +} diff --git a/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/main/java/org/eclipse/jetty/alpn/bouncycastle/client/BouncycastleClientALPNProcessor.java b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/main/java/org/eclipse/jetty/alpn/bouncycastle/client/BouncycastleClientALPNProcessor.java new file mode 100644 index 000000000000..55b1fbf2d34c --- /dev/null +++ b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/main/java/org/eclipse/jetty/alpn/bouncycastle/client/BouncycastleClientALPNProcessor.java @@ -0,0 +1,100 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.alpn.bouncycastle.client; + +import java.security.Security; +import java.util.List; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; +import org.eclipse.jetty.alpn.client.ALPNClientConnection; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.ssl.ALPNProcessor; +import org.eclipse.jetty.io.ssl.SslConnection.SslEndPoint; +import org.eclipse.jetty.io.ssl.SslHandshakeListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BouncycastleClientALPNProcessor implements ALPNProcessor.Client +{ + private static final Logger LOG = LoggerFactory.getLogger(BouncycastleClientALPNProcessor.class); + + @Override + public void init() + { + if (Security.getProvider("BCJSSE") == null) + { + Security.addProvider(new BouncyCastleJsseProvider()); + if (LOG.isDebugEnabled()) + LOG.debug("Added BouncyCastle JSSE provider"); + } + } + + @Override + public boolean appliesTo(SSLEngine sslEngine) + { + return sslEngine.getClass().getName().startsWith("org.bouncycastle.jsse.provider."); + } + + @Override + public void configure(SSLEngine sslEngine, Connection connection) + { + try + { + ALPNClientConnection alpn = (ALPNClientConnection)connection; + SSLParameters sslParameters = sslEngine.getSSLParameters(); + List protocols = alpn.getProtocols(); + sslParameters.setApplicationProtocols(protocols.toArray(new String[0])); + sslEngine.setSSLParameters(sslParameters); + SslEndPoint sslEndPoint = (SslEndPoint)connection.getEndPoint(); + sslEndPoint.getSslConnection().addHandshakeListener(new ALPNListener(alpn)); + } + catch (RuntimeException x) + { + throw x; + } + catch (Exception x) + { + throw new RuntimeException(x); + } + } + + private final class ALPNListener implements SslHandshakeListener + { + private final ALPNClientConnection alpnConnection; + + private ALPNListener(ALPNClientConnection connection) + { + alpnConnection = connection; + } + + @Override + public void handshakeSucceeded(Event event) + { + try + { + SSLEngine sslEngine = alpnConnection.getSSLEngine(); + String protocol = sslEngine.getApplicationProtocol(); + if (LOG.isDebugEnabled()) + LOG.debug("Selected {} for {}", protocol, alpnConnection); + alpnConnection.selected(protocol); + } + catch (Throwable e) + { + LOG.warn("Unable to process Bouncycastle ApplicationProtocol for {}", alpnConnection, e); + alpnConnection.selected(null); + } + } + } +} diff --git a/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/main/resources/META-INF/services/org.eclipse.jetty.io.ssl.ALPNProcessor$Client b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/main/resources/META-INF/services/org.eclipse.jetty.io.ssl.ALPNProcessor$Client new file mode 100644 index 000000000000..af7cfc2b9312 --- /dev/null +++ b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/main/resources/META-INF/services/org.eclipse.jetty.io.ssl.ALPNProcessor$Client @@ -0,0 +1 @@ +org.eclipse.jetty.alpn.bouncycastle.client.BouncycastleClientALPNProcessor diff --git a/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/test/java/org/eclipse/jetty/alpn/java/client/BouncycastleHTTP2ClientTest.java b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/test/java/org/eclipse/jetty/alpn/java/client/BouncycastleHTTP2ClientTest.java new file mode 100644 index 000000000000..e6500b9d42d2 --- /dev/null +++ b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/test/java/org/eclipse/jetty/alpn/java/client/BouncycastleHTTP2ClientTest.java @@ -0,0 +1,108 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.alpn.java.client; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.net.InetSocketAddress; +import java.net.Socket; +import java.security.Security; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.client.HTTP2Client; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.util.FuturePromise; +import org.eclipse.jetty.util.Jetty; +import org.eclipse.jetty.util.Promise; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +public class BouncycastleHTTP2ClientTest +{ + @Tag("external") + @Test + public void testBouncycastleHTTP2Client() throws Exception + { + String host = "webtide.com"; + int port = 443; + + Assumptions.assumeTrue(canConnectTo(host, port)); + + Security.insertProviderAt(new BouncyCastleJsseProvider(), 1); + SslContextFactory.Client sslContextFactory = new SslContextFactory.Client(); + sslContextFactory.setProvider("BCJSSE"); + + try (HTTP2Client client = new HTTP2Client()) + { + client.addBean(sslContextFactory); + client.start(); + + FuturePromise sessionPromise = new FuturePromise<>(); + client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener() {}, sessionPromise); + Session session = sessionPromise.get(15, TimeUnit.SECONDS); + + HttpFields requestFields = HttpFields.build().put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION); + MetaData.Request metaData = new MetaData.Request("GET", HttpURI.from("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields); + HeadersFrame headersFrame = new HeadersFrame(metaData, null, true); + CountDownLatch latch = new CountDownLatch(1); + session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + System.err.println(frame); + if (frame.isEndStream()) + latch.countDown(); + stream.demand(); + } + + @Override + public void onDataAvailable(Stream stream) + { + Stream.Data data = stream.readData(); + System.err.println(data); + data.release(); + if (data.frame().isEndStream()) + latch.countDown(); + else + stream.demand(); + } + }); + + assertTrue(latch.await(15, TimeUnit.SECONDS)); + } + } + + private boolean canConnectTo(String host, int port) + { + try + { + new Socket(host, port).close(); + return true; + } + catch (Throwable x) + { + return false; + } + } +} diff --git a/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/test/resources/jetty-logging.properties b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/test/resources/jetty-logging.properties new file mode 100644 index 000000000000..56cc73e5d684 --- /dev/null +++ b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-client/src/test/resources/jetty-logging.properties @@ -0,0 +1,2 @@ +# Jetty Logging using jetty-slf4j-impl +#org.eclipse.jetty.LEVEL=DEBUG diff --git a/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/pom.xml b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/pom.xml new file mode 100644 index 000000000000..a6f488e39058 --- /dev/null +++ b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/pom.xml @@ -0,0 +1,90 @@ + + + + 4.0.0 + + org.eclipse.jetty + jetty-alpn + 12.0.16-SNAPSHOT + + jetty-alpn-bouncycastle-server + Core :: ALPN :: Bouncy Castle Server + + + ${project.groupId}.alpn.bouncycastle.server + + + + + org.bouncycastle + bctls-fips + + + org.eclipse.jetty + jetty-alpn-server + + + org.eclipse.jetty + jetty-io + + + org.slf4j + slf4j-api + + + org.eclipse.jetty + jetty-alpn-conscrypt-client + test + + + org.eclipse.jetty + jetty-client + test + + + org.eclipse.jetty + jetty-slf4j-impl + test + + + org.eclipse.jetty.http2 + jetty-http2-client + test + + + org.eclipse.jetty.http2 + jetty-http2-client-transport + test + + + org.eclipse.jetty.http2 + jetty-http2-server + test + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + Bouncy Castle ALPN + ${osgi.slf4j.import.packages},org.bouncycastle;version="${bouncycastle.version}",* + osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional + osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server + <_nouses>true + + + + + maven-surefire-plugin + + @{argLine} ${jetty.surefire.argLine} --add-reads org.eclipse.jetty.alpn.bouncycastle.server=org.eclipse.jetty.server + + + + + diff --git a/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/main/java/module-info.java b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/main/java/module-info.java new file mode 100644 index 000000000000..14353f4aecc6 --- /dev/null +++ b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/main/java/module-info.java @@ -0,0 +1,25 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +import org.eclipse.jetty.alpn.bouncycastle.server.BouncycastleServerALPNProcessor; + +module org.eclipse.jetty.alpn.conscrypt.server +{ + requires org.slf4j; + + requires transitive org.eclipse.jetty.alpn.server; + requires org.bouncycastle.fips.tls; + + provides org.eclipse.jetty.io.ssl.ALPNProcessor.Server with + BouncycastleServerALPNProcessor; +} diff --git a/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/main/java/org/eclipse/jetty/alpn/bouncycastle/server/BouncycastleServerALPNProcessor.java b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/main/java/org/eclipse/jetty/alpn/bouncycastle/server/BouncycastleServerALPNProcessor.java new file mode 100644 index 000000000000..38277a393175 --- /dev/null +++ b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/main/java/org/eclipse/jetty/alpn/bouncycastle/server/BouncycastleServerALPNProcessor.java @@ -0,0 +1,89 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.alpn.bouncycastle.server; + +import java.util.List; +import java.util.function.BiFunction; +import javax.net.ssl.SSLEngine; +import org.eclipse.jetty.alpn.server.ALPNServerConnection; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.ssl.ALPNProcessor; +import org.eclipse.jetty.io.ssl.SslConnection.SslEndPoint; +import org.eclipse.jetty.io.ssl.SslHandshakeListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BouncycastleServerALPNProcessor implements ALPNProcessor.Server +{ + private static final Logger LOG = LoggerFactory.getLogger(BouncycastleServerALPNProcessor.class); + + @Override + public boolean appliesTo(SSLEngine sslEngine) + { + return sslEngine.getClass().getName().startsWith("org.bouncycastle.jsse.provider."); + } + + @Override + public void configure(SSLEngine sslEngine, Connection connection) + { + sslEngine.setHandshakeApplicationProtocolSelector(new ALPNCallback((ALPNServerConnection)connection)); + } + + private final class ALPNCallback implements BiFunction, String>, SslHandshakeListener + { + private final ALPNServerConnection alpnConnection; + + private ALPNCallback(ALPNServerConnection connection) + { + alpnConnection = connection; + SslEndPoint sslEndPoint = (SslEndPoint)alpnConnection.getEndPoint(); + sslEndPoint.getSslConnection().addHandshakeListener(this); + } + + @Override + public String apply(SSLEngine engine, List protocols) + { + try + { + if (LOG.isDebugEnabled()) + LOG.debug("apply {} {}", alpnConnection, protocols); + alpnConnection.select(protocols); + return alpnConnection.getProtocol(); + } + catch (Throwable x) + { + // Cannot negotiate the protocol, return null to have + // JSSE send Alert.NO_APPLICATION_PROTOCOL to the client. + return null; + } + } + + @Override + public void handshakeSucceeded(Event event) + { + String protocol = alpnConnection.getProtocol(); + if (LOG.isDebugEnabled()) + LOG.debug("TLS handshake succeeded, protocol={} for {}", protocol, alpnConnection); + if (protocol == null) + alpnConnection.unsupported(); + } + + @Override + public void handshakeFailed(Event event, Throwable failure) + { + if (LOG.isDebugEnabled()) + LOG.debug("TLS handshake failed {}", alpnConnection, failure); + } + } +} diff --git a/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/main/resources/META-INF/services/org.eclipse.jetty.io.ssl.ALPNProcessor$Server b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/main/resources/META-INF/services/org.eclipse.jetty.io.ssl.ALPNProcessor$Server new file mode 100644 index 000000000000..242bac9dde9d --- /dev/null +++ b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/main/resources/META-INF/services/org.eclipse.jetty.io.ssl.ALPNProcessor$Server @@ -0,0 +1 @@ +org.eclipse.jetty.alpn.bouncycastle.server.BouncycastleServerALPNProcessor diff --git a/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/test/java/org/eclipse/jetty/alpn/conscrypt/server/ConscryptHTTP2ServerTest.java b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/test/java/org/eclipse/jetty/alpn/conscrypt/server/ConscryptHTTP2ServerTest.java new file mode 100644 index 000000000000..576efa632b95 --- /dev/null +++ b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/test/java/org/eclipse/jetty/alpn/conscrypt/server/ConscryptHTTP2ServerTest.java @@ -0,0 +1,150 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.alpn.conscrypt.server; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.Security; + +import org.conscrypt.OpenSSLProvider; +import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; +import org.eclipse.jetty.client.ContentResponse; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.http2.client.HTTP2Client; +import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2; +import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; +import org.eclipse.jetty.io.ClientConnector; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.JavaVersion; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Test server that verifies that the Conscrypt ALPN mechanism works for both server and client side + */ +@DisabledOnOs(architectures = "aarch64", disabledReason = "Conscrypt does not provide aarch64 native libs as of version 2.5.2") +public class ConscryptHTTP2ServerTest +{ + static + { + Security.addProvider(new OpenSSLProvider()); + } + + private final HttpConfiguration httpsConfig = new HttpConfiguration(); + private final Server server = new Server(); + + private SslContextFactory.Server newServerSslContextFactory() + { + SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); + configureSslContextFactory(sslContextFactory); + return sslContextFactory; + } + + private SslContextFactory.Client newClientSslContextFactory() + { + SslContextFactory.Client sslContextFactory = new SslContextFactory.Client(); + configureSslContextFactory(sslContextFactory); + sslContextFactory.setEndpointIdentificationAlgorithm(null); + return sslContextFactory; + } + + private void configureSslContextFactory(SslContextFactory sslContextFactory) + { + Path path = Paths.get("src", "test", "resources"); + File keys = path.resolve("keystore.p12").toFile(); + sslContextFactory.setKeyStorePath(keys.getAbsolutePath()); + sslContextFactory.setKeyStorePassword("storepwd"); + sslContextFactory.setProvider("Conscrypt"); + if (JavaVersion.VERSION.getPlatform() < 9) + { + // Conscrypt enables TLSv1.3 by default but it's not supported in Java 8. + sslContextFactory.addExcludeProtocols("TLSv1.3"); + } + } + + @BeforeEach + public void startServer() throws Exception + { + httpsConfig.setSecureScheme("https"); + httpsConfig.setSendXPoweredBy(true); + httpsConfig.setSendServerVersion(true); + httpsConfig.addCustomizer(new SecureRequestCustomizer()); + + HttpConnectionFactory http = new HttpConnectionFactory(httpsConfig); + HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpsConfig); + ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); + alpn.setDefaultProtocol(http.getProtocol()); + SslConnectionFactory ssl = new SslConnectionFactory(newServerSslContextFactory(), alpn.getProtocol()); + + ServerConnector http2Connector = new ServerConnector(server, ssl, alpn, h2, http); + http2Connector.setPort(0); + server.addConnector(http2Connector); + + server.setHandler(new Handler.Abstract() + { + @Override + public boolean handle(Request request, Response response, Callback callback) + { + callback.succeeded(); + return true; + } + }); + + server.start(); + } + + @AfterEach + public void stopServer() throws Exception + { + server.stop(); + } + + @Test + public void testSimpleRequest() throws Exception + { + ClientConnector clientConnector = new ClientConnector(); + clientConnector.setSslContextFactory(newClientSslContextFactory()); + HTTP2Client h2Client = new HTTP2Client(clientConnector); + try (HttpClient client = new HttpClient(new HttpClientTransportOverHTTP2(h2Client))) + { + client.start(); + int port = ((ServerConnector)server.getConnectors()[0]).getLocalPort(); + ContentResponse contentResponse = client.GET("https://localhost:" + port); + assertEquals(200, contentResponse.getStatus()); + } + } + + @Test + public void testSNIRequired() throws Exception + { + // The KeyStore contains 1 certificate with two DNS names. + httpsConfig.getCustomizer(SecureRequestCustomizer.class).setSniRequired(true); + testSimpleRequest(); + } +} diff --git a/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/test/resources/jetty-logging.properties b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/test/resources/jetty-logging.properties new file mode 100644 index 000000000000..2f2fa6d19d9e --- /dev/null +++ b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +# Jetty Logging using jetty-slf4j-impl +#org.eclipse.jetty.LEVEL=DEBUG +#org.eclipse.jetty.alpn.LEVEL=DEBUG diff --git a/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/test/resources/keystore.p12 b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/test/resources/keystore.p12 new file mode 100644 index 000000000000..9c35858fe8d7 Binary files /dev/null and b/jetty-core/jetty-alpn/jetty-alpn-bouncycastle-server/src/test/resources/keystore.p12 differ diff --git a/jetty-core/jetty-alpn/pom.xml b/jetty-core/jetty-alpn/pom.xml index 1aa8b6857491..e2452f1949a8 100644 --- a/jetty-core/jetty-alpn/pom.xml +++ b/jetty-core/jetty-alpn/pom.xml @@ -14,6 +14,8 @@ jetty-alpn-client jetty-alpn-conscrypt-client jetty-alpn-conscrypt-server + jetty-alpn-bouncycastle-client + jetty-alpn-bouncycastle-server jetty-alpn-java-client jetty-alpn-java-server jetty-alpn-server diff --git a/pom.xml b/pom.xml index c91a0cc208f1..0907a4f65e6b 100644 --- a/pom.xml +++ b/pom.xml @@ -167,6 +167,7 @@ 9.7.1 4.2.2 7.0.0 + 2.0.19 3.6.0 1.5 3.2.1 @@ -609,6 +610,11 @@ awaitility ${awaitility.version} + + org.bouncycastle + bctls-fips + ${bouncycastle.version} + org.codehaus.plexus plexus-classworlds