diff --git a/pom.xml b/pom.xml
index acad23eabee..b2443e7e414 100644
--- a/pom.xml
+++ b/pom.xml
@@ -204,6 +204,11 @@
log4j-core
test
+
+ io.netty
+ netty-tcnative-classes
+ 2.0.75.Final-SNAPSHOT
+
io.netty
netty-tcnative-boringssl-static
diff --git a/src/main/asciidoc/http.adoc b/src/main/asciidoc/http.adoc
index 16b2d1bd91b..9a64219a2f9 100644
--- a/src/main/asciidoc/http.adoc
+++ b/src/main/asciidoc/http.adoc
@@ -41,6 +41,10 @@ To handle `h2` requests, TLS must be enabled along with {@link io.vertx.core.htt
{@link examples.HTTP2Examples#example0}
----
+The rise of quantum computers will make key exchange protocols such as x25519 obsolete as they will be able to "crack" secret keys quickly.
+Vert.x proposes a quantum-safe key exchange protocol, x25519MLKEM768 (official recommendation of NIST) to ensure sessions over TLS are safe against quantum computers.
+Hybrid key exchange must be enabled along with {@link io.vertx.core.http.HttpServerOptions#setUseHybrid(boolean)} and only works using OpenSsl ({$@link io.vertx.core.http.HttpServerOptions#setSslEngineOptions(SSLEngineOptions)})
+
ALPN is a TLS extension that negotiates the protocol before the client and the server start to exchange data.
Clients that don't support ALPN will still be able to do a _classic_ SSL handshake.
diff --git a/src/main/generated/io/vertx/core/eventbus/EventBusOptionsConverter.java b/src/main/generated/io/vertx/core/eventbus/EventBusOptionsConverter.java
index c750e1938bd..79e6fa8dfe5 100644
--- a/src/main/generated/io/vertx/core/eventbus/EventBusOptionsConverter.java
+++ b/src/main/generated/io/vertx/core/eventbus/EventBusOptionsConverter.java
@@ -279,6 +279,11 @@ static void fromJson(Iterable> json, EventBu
obj.setUseAlpn((Boolean)member.getValue());
}
break;
+ case "useHybrid":
+ if (member.getValue() instanceof Boolean) {
+ obj.setUseHybrid((Boolean)member.getValue());
+ }
+ break;
case "writeIdleTimeout":
if (member.getValue() instanceof Number) {
obj.setWriteIdleTimeout(((Number)member.getValue()).intValue());
@@ -388,6 +393,7 @@ static void toJson(EventBusOptions obj, java.util.Map json) {
json.put("trustStoreOptions", obj.getTrustStoreOptions().toJson());
}
json.put("useAlpn", obj.isUseAlpn());
+ json.put("useHybrid", obj.isUseHybrid());
json.put("writeIdleTimeout", obj.getWriteIdleTimeout());
}
}
diff --git a/src/main/generated/io/vertx/core/net/SSLOptionsConverter.java b/src/main/generated/io/vertx/core/net/SSLOptionsConverter.java
index ed5e57e40c9..76de6b53b5e 100644
--- a/src/main/generated/io/vertx/core/net/SSLOptionsConverter.java
+++ b/src/main/generated/io/vertx/core/net/SSLOptionsConverter.java
@@ -69,6 +69,11 @@ static void fromJson(Iterable> json, SSLOpti
obj.setUseAlpn((Boolean)member.getValue());
}
break;
+ case "useHybrid":
+ if (member.getValue() instanceof Boolean) {
+ obj.setUseHybrid((Boolean)member.getValue());
+ }
+ break;
}
}
}
@@ -103,5 +108,6 @@ static void toJson(SSLOptions obj, java.util.Map json) {
json.put("sslHandshakeTimeoutUnit", obj.getSslHandshakeTimeoutUnit().name());
}
json.put("useAlpn", obj.isUseAlpn());
+ json.put("useHybrid", obj.isUseHybrid());
}
}
diff --git a/src/main/generated/io/vertx/core/net/TCPSSLOptionsConverter.java b/src/main/generated/io/vertx/core/net/TCPSSLOptionsConverter.java
index 82392e43426..77b551b0262 100644
--- a/src/main/generated/io/vertx/core/net/TCPSSLOptionsConverter.java
+++ b/src/main/generated/io/vertx/core/net/TCPSSLOptionsConverter.java
@@ -179,6 +179,11 @@ static void fromJson(Iterable> json, TCPSSLO
obj.setUseAlpn((Boolean)member.getValue());
}
break;
+ case "useHybrid":
+ if (member.getValue() instanceof Boolean) {
+ obj.setUseHybrid((Boolean)member.getValue());
+ }
+ break;
case "writeIdleTimeout":
if (member.getValue() instanceof Number) {
obj.setWriteIdleTimeout(((Number)member.getValue()).intValue());
@@ -258,6 +263,7 @@ static void toJson(TCPSSLOptions obj, java.util.Map json) {
json.put("trustStoreOptions", obj.getTrustStoreOptions().toJson());
}
json.put("useAlpn", obj.isUseAlpn());
+ json.put("useHybrid", obj.isUseHybrid());
json.put("writeIdleTimeout", obj.getWriteIdleTimeout());
}
}
diff --git a/src/main/java/io/vertx/core/eventbus/EventBusOptions.java b/src/main/java/io/vertx/core/eventbus/EventBusOptions.java
index 955260e319d..85b2c6d7604 100644
--- a/src/main/java/io/vertx/core/eventbus/EventBusOptions.java
+++ b/src/main/java/io/vertx/core/eventbus/EventBusOptions.java
@@ -475,6 +475,11 @@ public EventBusOptions setUseAlpn(boolean useAlpn) {
return (EventBusOptions) super.setUseAlpn(useAlpn);
}
+ @Override
+ public EventBusOptions setUseHybrid(boolean useHybrid) {
+ return (EventBusOptions) super.setUseHybrid(useHybrid);
+ }
+
@Override
public EventBusOptions setSslEngineOptions(SSLEngineOptions sslEngineOptions) {
return (EventBusOptions) super.setSslEngineOptions(sslEngineOptions);
diff --git a/src/main/java/io/vertx/core/http/HttpClientOptions.java b/src/main/java/io/vertx/core/http/HttpClientOptions.java
index d5516ee040e..9cf2f3ed4dd 100755
--- a/src/main/java/io/vertx/core/http/HttpClientOptions.java
+++ b/src/main/java/io/vertx/core/http/HttpClientOptions.java
@@ -1154,6 +1154,11 @@ public HttpClientOptions setUseAlpn(boolean useAlpn) {
return (HttpClientOptions) super.setUseAlpn(useAlpn);
}
+ @Override
+ public HttpClientOptions setUseHybrid(boolean useHybrid) {
+ return (HttpClientOptions) super.setUseHybrid(useHybrid);
+ }
+
@Override
public HttpClientOptions setSslEngineOptions(SSLEngineOptions sslEngineOptions) {
return (HttpClientOptions) super.setSslEngineOptions(sslEngineOptions);
diff --git a/src/main/java/io/vertx/core/http/HttpServerOptions.java b/src/main/java/io/vertx/core/http/HttpServerOptions.java
index 345c804f862..917b57c3506 100755
--- a/src/main/java/io/vertx/core/http/HttpServerOptions.java
+++ b/src/main/java/io/vertx/core/http/HttpServerOptions.java
@@ -421,6 +421,18 @@ public HttpServerOptions setUseAlpn(boolean useAlpn) {
return this;
}
+ /*
+ Use X25519MLKEM768 instead of X25519 for key exchange.
+ X25519MLKEM768 is a hybrid protocol exchange ensuring that encryption will resist quantum computers
+ */
+ @Override
+ public HttpServerOptions setUseHybrid(boolean useHybrid) {
+ super.setUseHybrid(useHybrid);
+ return this;
+ }
+
+
+
@Override
public HttpServerOptions setKeyCertOptions(KeyCertOptions options) {
super.setKeyCertOptions(options);
diff --git a/src/main/java/io/vertx/core/http/WebSocketClientOptions.java b/src/main/java/io/vertx/core/http/WebSocketClientOptions.java
index 2fa6757755d..abb0f2c89a9 100644
--- a/src/main/java/io/vertx/core/http/WebSocketClientOptions.java
+++ b/src/main/java/io/vertx/core/http/WebSocketClientOptions.java
@@ -552,6 +552,11 @@ public WebSocketClientOptions setUseAlpn(boolean useAlpn) {
return (WebSocketClientOptions)super.setUseAlpn(useAlpn);
}
+ @Override
+ public WebSocketClientOptions setUseHybrid(boolean useHybrid) {
+ return (WebSocketClientOptions)super.setUseHybrid(useHybrid);
+ }
+
@Override
public WebSocketClientOptions setSslEngineOptions(SSLEngineOptions sslEngineOptions) {
return (WebSocketClientOptions)super.setSslEngineOptions(sslEngineOptions);
diff --git a/src/main/java/io/vertx/core/http/impl/HttpServerWorker.java b/src/main/java/io/vertx/core/http/impl/HttpServerWorker.java
index f783d9a333e..e1b2d34f044 100644
--- a/src/main/java/io/vertx/core/http/impl/HttpServerWorker.java
+++ b/src/main/java/io/vertx/core/http/impl/HttpServerWorker.java
@@ -33,9 +33,12 @@
import io.vertx.core.impl.VertxInternal;
import io.vertx.core.net.impl.*;
import io.vertx.core.spi.metrics.HttpServerMetrics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.List;
+import java.util.concurrent.ExecutionException;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -61,6 +64,7 @@ public class HttpServerWorker implements BiConsumer
private final CompressionOptions[] compressionOptions;
private final Function encodingDetector;
private final GlobalTrafficShapingHandler trafficShapingHandler;
+ private static final Logger log = LoggerFactory.getLogger(SslChannelProvider.class);
public HttpServerWorker(ContextInternal context,
Supplier streamContextSupplier,
@@ -115,18 +119,28 @@ public void accept(Channel ch, SslChannelProvider sslChannelProvider) {
if (idle != null) {
ch.pipeline().remove(idle);
}
- configurePipeline(future.getNow(), sslChannelProvider);
+ try {
+ configurePipeline(future.getNow(), sslChannelProvider);
+ } catch (Exception e) {
+ log.error(e.getMessage()+ ", now closing the channel");
+ ch.close();
+ }
} else {
//No need to close the channel.HAProxyMessageDecoder already did
handleException(future.cause());
}
});
} else {
- configurePipeline(ch, sslChannelProvider);
+ try {
+ configurePipeline(ch, sslChannelProvider);
+ } catch (Exception e) {
+ log.error(e.getMessage()+ ", now closing the channel");
+ ch.close();
+ }
}
}
- private void configurePipeline(Channel ch, SslChannelProvider sslChannelProvider) {
+ private void configurePipeline(Channel ch, SslChannelProvider sslChannelProvider) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
if (options.isSsl()) {
pipeline.addLast("ssl", sslChannelProvider.createServerHandler(HttpUtils.socketAddressToHostAndPort(ch.remoteAddress())));
diff --git a/src/main/java/io/vertx/core/net/ClientOptionsBase.java b/src/main/java/io/vertx/core/net/ClientOptionsBase.java
index 2fb8b876042..703e34c6bd6 100755
--- a/src/main/java/io/vertx/core/net/ClientOptionsBase.java
+++ b/src/main/java/io/vertx/core/net/ClientOptionsBase.java
@@ -340,6 +340,11 @@ public ClientOptionsBase setUseAlpn(boolean useAlpn) {
return (ClientOptionsBase) super.setUseAlpn(useAlpn);
}
+ @Override
+ public ClientOptionsBase setUseHybrid(boolean useHyrbrid) {
+ return (ClientOptionsBase) super.setUseHybrid(useHyrbrid);
+ }
+
@Override
public ClientOptionsBase setSslEngineOptions(SSLEngineOptions sslEngineOptions) {
return (ClientOptionsBase) super.setSslEngineOptions(sslEngineOptions);
diff --git a/src/main/java/io/vertx/core/net/NetClientOptions.java b/src/main/java/io/vertx/core/net/NetClientOptions.java
index 5c9fcd56120..b605b73311d 100755
--- a/src/main/java/io/vertx/core/net/NetClientOptions.java
+++ b/src/main/java/io/vertx/core/net/NetClientOptions.java
@@ -263,6 +263,11 @@ public NetClientOptions setUseAlpn(boolean useAlpn) {
return (NetClientOptions) super.setUseAlpn(useAlpn);
}
+ @Override
+ public NetClientOptions setUseHybrid(boolean useHybrid) {
+ return (NetClientOptions) super.setUseHybrid(useHybrid);
+ }
+
@Override
public NetClientOptions setSslEngineOptions(SSLEngineOptions sslEngineOptions) {
return (NetClientOptions) super.setSslEngineOptions(sslEngineOptions);
diff --git a/src/main/java/io/vertx/core/net/NetServerOptions.java b/src/main/java/io/vertx/core/net/NetServerOptions.java
index 125b079d4a6..3a1eb907e6c 100755
--- a/src/main/java/io/vertx/core/net/NetServerOptions.java
+++ b/src/main/java/io/vertx/core/net/NetServerOptions.java
@@ -221,8 +221,8 @@ public NetServerOptions setSsl(boolean ssl) {
}
@Override
- public NetServerOptions setUseAlpn(boolean useAlpn) {
- super.setUseAlpn(useAlpn);
+ public NetServerOptions setUseHybrid(boolean useHybrid) {
+ super.setUseHybrid(useHybrid);
return this;
}
diff --git a/src/main/java/io/vertx/core/net/SSLOptions.java b/src/main/java/io/vertx/core/net/SSLOptions.java
index ed3f0bc0f69..f01f6e6da85 100644
--- a/src/main/java/io/vertx/core/net/SSLOptions.java
+++ b/src/main/java/io/vertx/core/net/SSLOptions.java
@@ -37,7 +37,11 @@ public class SSLOptions {
/**
* Default use alpn = false
*/
- public static final boolean DEFAULT_USE_ALPN = false;
+ public static final boolean DEFAULT_USE_ALPN = false; /**
+
+ * Default use hybrid = false
+ */
+ public static final boolean DEFAULT_USE_HYBRID = false;
/**
* The default value of SSL handshake timeout = 10
@@ -66,6 +70,7 @@ public class SSLOptions {
private ArrayList crlPaths;
private ArrayList crlValues;
private boolean useAlpn;
+ private boolean useHybrid;
private Set enabledSecureTransportProtocols;
/**
@@ -99,6 +104,7 @@ public SSLOptions(SSLOptions other) {
this.crlPaths = new ArrayList<>(other.getCrlPaths());
this.crlValues = new ArrayList<>(other.getCrlValues());
this.useAlpn = other.useAlpn;
+ this.useHybrid = other.useHybrid;
this.enabledSecureTransportProtocols = other.getEnabledSecureTransportProtocols() == null ? new LinkedHashSet<>() : new LinkedHashSet<>(other.getEnabledSecureTransportProtocols());
}
@@ -110,6 +116,7 @@ private void init() {
crlPaths = new ArrayList<>();
crlValues = new ArrayList<>();
useAlpn = DEFAULT_USE_ALPN;
+ useHybrid = DEFAULT_USE_HYBRID;
enabledSecureTransportProtocols = new LinkedHashSet<>(DEFAULT_ENABLED_SECURE_TRANSPORT_PROTOCOLS);
}
@@ -236,6 +243,13 @@ public boolean isUseAlpn() {
return useAlpn;
}
+ /**
+ * @return whether to use or not Hybrid key exchange protocol x25519MLKEM768
+ */
+ public boolean isUseHybrid() {
+ return useHybrid;
+ }
+
/**
* Set the ALPN usage.
*
@@ -246,6 +260,11 @@ public SSLOptions setUseAlpn(boolean useAlpn) {
return this;
}
+ public SSLOptions setUseHybrid(boolean useHybrid) {
+ this.useHybrid = useHybrid;
+ return this;
+ }
+
/**
* Returns the enabled SSL/TLS protocols
* @return the enabled protocols
diff --git a/src/main/java/io/vertx/core/net/TCPSSLOptions.java b/src/main/java/io/vertx/core/net/TCPSSLOptions.java
index 3b2f6e569df..6204d905ce1 100755
--- a/src/main/java/io/vertx/core/net/TCPSSLOptions.java
+++ b/src/main/java/io/vertx/core/net/TCPSSLOptions.java
@@ -712,6 +712,13 @@ public boolean isUseAlpn() {
return sslOptions.isUseAlpn();
}
+ /**
+ * @return whether to use or not Hybrid key exchange protocol x25519MLKEM768
+ */
+ public boolean isUseHybrid() {
+ return sslOptions.isUseHybrid();
+ }
+
/**
* Set the ALPN usage.
*
@@ -722,6 +729,11 @@ public TCPSSLOptions setUseAlpn(boolean useAlpn) {
return this;
}
+ public TCPSSLOptions setUseHybrid(boolean useHybrid) {
+ sslOptions.setUseHybrid(useHybrid);
+ return this;
+ }
+
/**
* @return the SSL engine implementation to use
*/
diff --git a/src/main/java/io/vertx/core/net/impl/ChannelProvider.java b/src/main/java/io/vertx/core/net/impl/ChannelProvider.java
index 10006a636e3..7d5d1266d16 100644
--- a/src/main/java/io/vertx/core/net/impl/ChannelProvider.java
+++ b/src/main/java/io/vertx/core/net/impl/ChannelProvider.java
@@ -34,6 +34,8 @@
import io.vertx.core.net.ProxyOptions;
import io.vertx.core.net.ProxyType;
import io.vertx.core.net.SocketAddress;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLHandshakeException;
import java.net.InetAddress;
@@ -49,6 +51,7 @@
*/
public final class ChannelProvider {
+ private static final Logger log = LoggerFactory.getLogger(ChannelProvider.class);
private final Bootstrap bootstrap;
private final SslChannelProvider sslContextProvider;
private final ContextInternal context;
@@ -115,9 +118,17 @@ private void connect(Handler handler, SocketAddress remoteAddress, Sock
private void initSSL(Handler handler, SocketAddress peerAddress, String serverName, boolean ssl, boolean useAlpn, Channel ch, Promise channelHandler) {
if (ssl) {
- SslHandler sslHandler = sslContextProvider.createClientSslHandler(peerAddress, serverName, useAlpn);
+ SslHandler sslHandler = null;
+ try {
+ sslHandler = sslContextProvider.createClientSslHandler(peerAddress, serverName, useAlpn);
+ } catch (Exception e) {
+ log.error(e.getMessage());
+ ch.close();
+ return;
+ }
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("ssl", sslHandler);
+ SslHandler finalSslHandler = sslHandler;
pipeline.addLast(new ChannelInboundHandlerAdapter() {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
@@ -127,7 +138,7 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (completion.isSuccess()) {
// Remove from the pipeline after handshake result
ctx.pipeline().remove(this);
- applicationProtocol = sslHandler.applicationProtocol();
+ applicationProtocol = finalSslHandler.applicationProtocol();
if (handler != null) {
context.dispatch(ch, handler);
}
diff --git a/src/main/java/io/vertx/core/net/impl/NetServerImpl.java b/src/main/java/io/vertx/core/net/impl/NetServerImpl.java
index 9f8c3ca4949..a47925e94df 100644
--- a/src/main/java/io/vertx/core/net/impl/NetServerImpl.java
+++ b/src/main/java/io/vertx/core/net/impl/NetServerImpl.java
@@ -39,6 +39,7 @@
import io.vertx.core.spi.metrics.VertxMetrics;
import io.vertx.core.streams.ReadStream;
+import java.util.concurrent.ExecutionException;
import java.util.function.BiConsumer;
/**
@@ -209,18 +210,28 @@ public void accept(Channel ch, SslChannelProvider sslChannelProvider) {
if (idle != null) {
ch.pipeline().remove(idle);
}
- configurePipeline(future.getNow(), sslChannelProvider);
+ try {
+ configurePipeline(future.getNow(), sslChannelProvider);
+ } catch (Exception e) {
+ log.error(e.getMessage()+ ", now closing the channel");
+ ch.close();
+ }
} else {
//No need to close the channel.HAProxyMessageDecoder already did
handleException(future.cause());
}
});
} else {
- configurePipeline(ch, sslChannelProvider);
+ try {
+ configurePipeline(ch, sslChannelProvider);
+ } catch (Exception e) {
+ log.error(e.getMessage()+ ", now closing the channel");
+ ch.close();
+ }
}
}
- private void configurePipeline(Channel ch, SslChannelProvider sslChannelProvider) {
+ private void configurePipeline(Channel ch, SslChannelProvider sslChannelProvider) throws Exception{
if (options.isSsl()) {
ch.pipeline().addLast("ssl", sslChannelProvider.createServerHandler(HttpUtils.socketAddressToHostAndPort(ch.remoteAddress())));
ChannelPromise p = ch.newPromise();
diff --git a/src/main/java/io/vertx/core/net/impl/NetSocketImpl.java b/src/main/java/io/vertx/core/net/impl/NetSocketImpl.java
index 883b653591f..4b8a2c001df 100644
--- a/src/main/java/io/vertx/core/net/impl/NetSocketImpl.java
+++ b/src/main/java/io/vertx/core/net/impl/NetSocketImpl.java
@@ -338,7 +338,12 @@ public Future upgradeToSsl(String serverName) {
if (remoteAddress != null) {
sslHandler = sslChannelProvider.createClientSslHandler(remoteAddress, serverName, false);
} else {
- sslHandler = sslChannelProvider.createServerHandler(HttpUtils.socketAddressToHostAndPort(chctx.channel().remoteAddress()));
+ try {
+ sslHandler = sslChannelProvider.createServerHandler(HttpUtils.socketAddressToHostAndPort(chctx.channel().remoteAddress()));
+ } catch (Exception e) {
+ promise.fail(e);
+ return;
+ }
}
chctx.pipeline().addFirst("ssl", sslHandler);
} else {
diff --git a/src/main/java/io/vertx/core/net/impl/SSLHelper.java b/src/main/java/io/vertx/core/net/impl/SSLHelper.java
index 17747e45702..50ac4700abe 100755
--- a/src/main/java/io/vertx/core/net/impl/SSLHelper.java
+++ b/src/main/java/io/vertx/core/net/impl/SSLHelper.java
@@ -128,6 +128,7 @@ public static SSLEngineOptions resolveEngineOptions(SSLEngineOptions engineOptio
private final ClientAuth clientAuth;
private final boolean client;
private final boolean useAlpn;
+ private final boolean useHybrid;
private final String endpointIdentificationAlgorithm;
private final SSLEngineOptions sslEngineOptions;
private final List applicationProtocols;
@@ -139,6 +140,7 @@ public static SSLEngineOptions resolveEngineOptions(SSLEngineOptions engineOptio
private Future cachedProvider;
public SSLHelper(TCPSSLOptions options, List applicationProtocols) {
+ this.useHybrid = options.isUseHybrid();
this.sslEngineOptions = options.getSslEngineOptions();
this.ssl = options.isSsl();
this.useAlpn = options.isUseAlpn();
@@ -264,7 +266,8 @@ public Future buildChannelProvider(SSLOptions sslOptions, Co
trustAll,
useAlpn,
ctx.owner().getInternalWorkerPool().executor(),
- c.useWorkerPool
+ c.useWorkerPool,
+ useHybrid
));
}
diff --git a/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java b/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java
index 4c54eb412b9..2357e75d9ce 100644
--- a/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java
+++ b/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java
@@ -11,20 +11,28 @@
package io.vertx.core.net.impl;
import io.netty.buffer.ByteBufAllocator;
+import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.ssl.ReferenceCountedOpenSslEngine;
import io.netty.handler.ssl.SniHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslHandler;
+import io.netty.internal.tcnative.SSL;
import io.netty.util.AsyncMapping;
import io.netty.util.concurrent.ImmediateExecutor;
import io.vertx.core.VertxException;
import io.vertx.core.net.HostAndPort;
import io.vertx.core.net.SocketAddress;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -35,12 +43,14 @@
*/
public class SslChannelProvider {
+ private static final Logger log = LoggerFactory.getLogger(SslChannelProvider.class);
private final long sslHandshakeTimeout;
private final TimeUnit sslHandshakeTimeoutUnit;
private final Executor workerPool;
private final boolean useWorkerPool;
private final boolean sni;
private final boolean useAlpn;
+ private final boolean useHybrid;
private final boolean trustAll;
private final SslContextProvider sslContextProvider;
private final SslContext[] sslContexts = new SslContext[2];
@@ -55,7 +65,7 @@ public SslChannelProvider(SslContextProvider sslContextProvider,
boolean trustAll,
boolean useAlpn,
Executor workerPool,
- boolean useWorkerPool) {
+ boolean useWorkerPool, boolean useHybrid) {
this.workerPool = workerPool;
this.useWorkerPool = useWorkerPool;
this.useAlpn = useAlpn;
@@ -64,6 +74,7 @@ public SslChannelProvider(SslContextProvider sslContextProvider,
this.sslHandshakeTimeout = sslHandshakeTimeout;
this.sslHandshakeTimeoutUnit = sslHandshakeTimeoutUnit;
this.sslContextProvider = sslContextProvider;
+ this.useHybrid = useHybrid;
}
public int sniEntrySize() {
@@ -131,7 +142,7 @@ public SslContext sslServerContext(boolean useAlpn) {
};
}
- public SslHandler createClientSslHandler(SocketAddress remoteAddress, String serverName, boolean useAlpn) {
+ public SslHandler createClientSslHandler(SocketAddress remoteAddress, String serverName, boolean useAlpn) throws Exception {
SslContext sslContext = sslClientContext(serverName, useAlpn);
SslHandler sslHandler;
Executor delegatedTaskExec = useWorkerPool ? workerPool : ImmediateExecutor.INSTANCE;
@@ -140,19 +151,35 @@ public SslHandler createClientSslHandler(SocketAddress remoteAddress, String ser
} else {
sslHandler = sslContext.newHandler(ByteBufAllocator.DEFAULT, remoteAddress.host(), remoteAddress.port(), delegatedTaskExec);
}
+ if (useHybrid) {
+ SSLEngine engine = sslHandler.engine();
+ try {
+ long sslPtr = ((ReferenceCountedOpenSslEngine) engine).sslPointer();
+ boolean success = SSL.setCurvesList(sslPtr, "X25519MLKEM768");
+ if (!success) {
+ throw new Exception("Failed to set hybrid PQC groups on SSL instance");
+ }
+ } catch (Exception e) {
+ throw new Exception("Unable to create sslHandler: "+e.getMessage());
+ }
+ }
sslHandler.setHandshakeTimeout(sslHandshakeTimeout, sslHandshakeTimeoutUnit);
return sslHandler;
}
- public ChannelHandler createServerHandler(HostAndPort remoteAddress) {
+ public ChannelHandler createServerHandler(HostAndPort remoteAddress) throws Exception {
if (sni) {
- return createSniHandler(remoteAddress);
+ SniHandler sniHandler = createSniHandler(useHybrid, remoteAddress);
+ if(sniHandler == null){
+ throw new Exception("Unable to create a SNI handler");
+ }
+ return sniHandler;
} else {
- return createServerSslHandler(useAlpn, remoteAddress);
+ return createServerSslHandler(useAlpn, useHybrid, remoteAddress);
}
}
- private SslHandler createServerSslHandler(boolean useAlpn, HostAndPort remoteAddress) {
+ private SslHandler createServerSslHandler(boolean useAlpn, boolean useHybrid, HostAndPort remoteAddress) throws Exception {
SslContext sslContext = sslServerContext(useAlpn);
Executor delegatedTaskExec = useWorkerPool ? workerPool : ImmediateExecutor.INSTANCE;
SslHandler sslHandler;
@@ -161,13 +188,26 @@ private SslHandler createServerSslHandler(boolean useAlpn, HostAndPort remoteAdd
} else {
sslHandler = sslContext.newHandler(ByteBufAllocator.DEFAULT, delegatedTaskExec);
}
+ if (useHybrid) {
+ SSLEngine engine = sslHandler.engine();
+ try {
+ long sslPtr = ((ReferenceCountedOpenSslEngine) engine).sslPointer();
+ boolean success = SSL.setCurvesList(sslPtr, "X25519MLKEM768");
+ if (!success) {
+ throw new Exception("Failed to set hybrid PQC groups on SSL instance");
+ }
+ } catch (Exception e) {
+ throw new Exception("Unable to create sslHandler: "+e.getMessage());
+ }
+ }
sslHandler.setHandshakeTimeout(sslHandshakeTimeout, sslHandshakeTimeoutUnit);
return sslHandler;
}
- private SniHandler createSniHandler(HostAndPort remoteAddress) {
+ private SniHandler createSniHandler(boolean useHybrid, HostAndPort remoteAddress) {
Executor delegatedTaskExec = useWorkerPool ? workerPool : ImmediateExecutor.INSTANCE;
- return new VertxSniHandler(serverNameMapping(), sslHandshakeTimeoutUnit.toMillis(sslHandshakeTimeout), delegatedTaskExec, remoteAddress);
+ return new VertxSniHandler(serverNameMapping(), sslHandshakeTimeoutUnit.toMillis(sslHandshakeTimeout), delegatedTaskExec,
+ useHybrid, remoteAddress);
}
private static int idx(boolean useAlpn) {
diff --git a/src/main/java/io/vertx/core/net/impl/VertxSniHandler.java b/src/main/java/io/vertx/core/net/impl/VertxSniHandler.java
index 07142c6d1c4..a3357d3f64b 100644
--- a/src/main/java/io/vertx/core/net/impl/VertxSniHandler.java
+++ b/src/main/java/io/vertx/core/net/impl/VertxSniHandler.java
@@ -11,12 +11,17 @@
package io.vertx.core.net.impl;
import io.netty.buffer.ByteBufAllocator;
+import io.netty.handler.ssl.ReferenceCountedOpenSslEngine;
import io.netty.handler.ssl.SniHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslHandler;
+import io.netty.internal.tcnative.SSL;
import io.netty.util.AsyncMapping;
import io.vertx.core.net.HostAndPort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.net.ssl.SSLEngine;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -29,12 +34,16 @@ class VertxSniHandler extends SniHandler {
private final Executor delegatedTaskExec;
private final HostAndPort remoteAddress;
+ private final boolean useHybrid;
+
+ private static final Logger log = LoggerFactory.getLogger(SslChannelProvider.class);
public VertxSniHandler(AsyncMapping super String, ? extends SslContext> mapping, long handshakeTimeoutMillis, Executor delegatedTaskExec,
- HostAndPort remoteAddress) {
+ boolean useHybrid, HostAndPort remoteAddress) {
super(mapping, handshakeTimeoutMillis);
this.delegatedTaskExec = delegatedTaskExec;
+ this.useHybrid = useHybrid;
this.remoteAddress = remoteAddress;
}
@@ -46,6 +55,22 @@ protected SslHandler newSslHandler(SslContext context, ByteBufAllocator allocato
} else {
sslHandler = context.newHandler(allocator, delegatedTaskExec);
}
+ if(useHybrid){
+ SSLEngine engine = sslHandler.engine();
+ try {
+ long sslPtr = ((ReferenceCountedOpenSslEngine) engine).sslPointer();
+ boolean success = SSL.setCurvesList(sslPtr, "X25519MLKEM768");
+ if (!success) {
+ throw new Exception("Failed to set hybrid PQC groups on SSL instance");
+ }
+ } catch (Exception e) {
+ /*
+ todo : would like to throw instead of returning null to be consistent with
+ io.vertx.core.net.impl.SslChannelProvider.createServerSslHandler(...) but can't as we extend a netty class here.
+ */
+ return null;
+ }
+ }
sslHandler.setHandshakeTimeout(handshakeTimeoutMillis, TimeUnit.MILLISECONDS);
return sslHandler;
}