Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,11 @@
<artifactId>log4j-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-classes</artifactId>
<version>2.0.75.Final-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
Expand Down
4 changes: 4 additions & 0 deletions src/main/asciidoc/http.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,11 @@ static void fromJson(Iterable<java.util.Map.Entry<String, Object>> 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());
Expand Down Expand Up @@ -388,6 +393,7 @@ static void toJson(EventBusOptions obj, java.util.Map<String, Object> json) {
json.put("trustStoreOptions", obj.getTrustStoreOptions().toJson());
}
json.put("useAlpn", obj.isUseAlpn());
json.put("useHybrid", obj.isUseHybrid());
json.put("writeIdleTimeout", obj.getWriteIdleTimeout());
}
}
6 changes: 6 additions & 0 deletions src/main/generated/io/vertx/core/net/SSLOptionsConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, SSLOpti
obj.setUseAlpn((Boolean)member.getValue());
}
break;
case "useHybrid":
if (member.getValue() instanceof Boolean) {
obj.setUseHybrid((Boolean)member.getValue());
}
break;
}
}
}
Expand Down Expand Up @@ -103,5 +108,6 @@ static void toJson(SSLOptions obj, java.util.Map<String, Object> json) {
json.put("sslHandshakeTimeoutUnit", obj.getSslHandshakeTimeoutUnit().name());
}
json.put("useAlpn", obj.isUseAlpn());
json.put("useHybrid", obj.isUseHybrid());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ static void fromJson(Iterable<java.util.Map.Entry<String, Object>> 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());
Expand Down Expand Up @@ -258,6 +263,7 @@ static void toJson(TCPSSLOptions obj, java.util.Map<String, Object> json) {
json.put("trustStoreOptions", obj.getTrustStoreOptions().toJson());
}
json.put("useAlpn", obj.isUseAlpn());
json.put("useHybrid", obj.isUseHybrid());
json.put("writeIdleTimeout", obj.getWriteIdleTimeout());
}
}
5 changes: 5 additions & 0 deletions src/main/java/io/vertx/core/eventbus/EventBusOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/io/vertx/core/http/HttpClientOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/io/vertx/core/http/HttpServerOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/io/vertx/core/http/WebSocketClientOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
20 changes: 17 additions & 3 deletions src/main/java/io/vertx/core/http/impl/HttpServerWorker.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -61,6 +64,7 @@ public class HttpServerWorker implements BiConsumer<Channel, SslChannelProvider>
private final CompressionOptions[] compressionOptions;
private final Function<String, String> encodingDetector;
private final GlobalTrafficShapingHandler trafficShapingHandler;
private static final Logger log = LoggerFactory.getLogger(SslChannelProvider.class);

public HttpServerWorker(ContextInternal context,
Supplier<ContextInternal> streamContextSupplier,
Expand Down Expand Up @@ -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())));
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/io/vertx/core/net/ClientOptionsBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/io/vertx/core/net/NetClientOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/io/vertx/core/net/NetServerOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
21 changes: 20 additions & 1 deletion src/main/java/io/vertx/core/net/SSLOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -66,6 +70,7 @@ public class SSLOptions {
private ArrayList<String> crlPaths;
private ArrayList<Buffer> crlValues;
private boolean useAlpn;
private boolean useHybrid;
private Set<String> enabledSecureTransportProtocols;

/**
Expand Down Expand Up @@ -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());
}

Expand All @@ -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);
}

Expand Down Expand Up @@ -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.
*
Expand All @@ -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
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/io/vertx/core/net/TCPSSLOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -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
*/
Expand Down
15 changes: 13 additions & 2 deletions src/main/java/io/vertx/core/net/impl/ChannelProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -115,9 +118,17 @@ private void connect(Handler<Channel> handler, SocketAddress remoteAddress, Sock

private void initSSL(Handler<Channel> handler, SocketAddress peerAddress, String serverName, boolean ssl, boolean useAlpn, Channel ch, Promise<Channel> 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) {
Expand All @@ -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);
}
Expand Down
17 changes: 14 additions & 3 deletions src/main/java/io/vertx/core/net/impl/NetServerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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();
Expand Down
Loading