Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TLS/mTLS options for websockets (#7854) #16

Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,71 @@ public class RpcWebsocketOptions {
arity = "1")
private final File rpcWsAuthenticationPublicKeyFile = null;

@CommandLine.Option(
names = {"--rpc-ws-ssl-enabled"},
description = "Enable SSL/TLS for the WebSocket RPC service")
private final Boolean isRpcWsSslEnabled = false;

@CommandLine.Option(
names = {"--rpc-ws-ssl-keystore-file"},
paramLabel = DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP,
description = "Path to the keystore file for the WebSocket RPC service")
private String rpcWsKeyStoreFile = null;

@CommandLine.Option(
names = {"--rpc-ws-ssl-keystore-password"},
paramLabel = "<PASSWORD>",
description = "Password for the WebSocket RPC keystore file")
private String rpcWsKeyStorePassword = null;

@CommandLine.Option(
names = {"--rpc-ws-ssl-key-file"},
paramLabel = DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP,
description = "Path to the PEM key file for the WebSocket RPC service")
private String rpcWsKeyFile = null;

@CommandLine.Option(
names = {"--rpc-ws-ssl-cert-file"},
paramLabel = DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP,
description = "Path to the PEM cert file for the WebSocket RPC service")
private String rpcWsCertFile = null;

@CommandLine.Option(
names = {"--rpc-ws-ssl-keystore-type"},
paramLabel = "<TYPE>",
description = "Type of the WebSocket RPC keystore (JKS, PKCS12, PEM)")
private String rpcWsKeyStoreType = null;

// For client authentication (mTLS)
@CommandLine.Option(
names = {"--rpc-ws-ssl-client-auth-enabled"},
description = "Enable client authentication for the WebSocket RPC service")
private final Boolean isRpcWsClientAuthEnabled = false;

@CommandLine.Option(
names = {"--rpc-ws-ssl-truststore-file"},
paramLabel = DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP,
description = "Path to the truststore file for the WebSocket RPC service")
private String rpcWsTrustStoreFile = null;

@CommandLine.Option(
names = {"--rpc-ws-ssl-truststore-password"},
paramLabel = "<PASSWORD>",
description = "Password for the WebSocket RPC truststore file")
private String rpcWsTrustStorePassword = null;

@CommandLine.Option(
names = {"--rpc-ws-ssl-trustcert-file"},
paramLabel = DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP,
description = "Path to the PEM trustcert file for the WebSocket RPC service")
private String rpcWsTrustCertFile = null;

@CommandLine.Option(
names = {"--rpc-ws-ssl-truststore-type"},
paramLabel = "<TYPE>",
description = "Type of the truststore (JKS, PKCS12, PEM)")
private String rpcWsTrustStoreType = null;

/** Default Constructor. */
public RpcWebsocketOptions() {}

Expand Down Expand Up @@ -184,7 +249,61 @@ private void checkOptionDependencies(final Logger logger, final CommandLine comm
"--rpc-ws-authentication-enabled",
"--rpc-ws-authentication-credentials-file",
"--rpc-ws-authentication-public-key-file",
"--rpc-ws-authentication-jwt-algorithm"));
"--rpc-ws-authentication-jwt-algorithm",
"--rpc-ws-ssl-enabled"));

CommandLineUtils.checkOptionDependencies(
logger,
commandLine,
"--rpc-ws-ssl-enabled",
!isRpcWsSslEnabled,
List.of(
"--rpc-ws-ssl-keystore-file",
"--rpc-ws-ssl-keystore-type",
"--rpc-ws-ssl-client-auth-enabled"));

CommandLineUtils.checkOptionDependencies(
logger,
commandLine,
"--rpc-ws-ssl-client-auth-enabled",
!isRpcWsClientAuthEnabled,
List.of(
"--rpc-ws-ssl-truststore-file",
"--rpc-ws-ssl-truststore-type",
"--rpc-ws-ssl-trustcert-file"));

if (isRpcWsSslEnabled) {
if ("PEM".equalsIgnoreCase(rpcWsKeyStoreType)) {
CommandLineUtils.checkOptionDependencies(
logger,
commandLine,
"--rpc-ws-ssl-key-file",
rpcWsKeyFile == null,
List.of("--rpc-ws-ssl-cert-file"));
CommandLineUtils.checkOptionDependencies(
logger,
commandLine,
"--rpc-ws-ssl-cert-file",
rpcWsCertFile == null,
List.of("--rpc-ws-ssl-key-file"));
} else {
CommandLineUtils.checkOptionDependencies(
logger,
commandLine,
"--rpc-ws-ssl-keystore-file",
rpcWsKeyStoreFile == null,
List.of("--rpc-ws-ssl-keystore-password"));
}
}

if (isRpcWsClientAuthEnabled && !"PEM".equalsIgnoreCase(rpcWsTrustStoreType)) {
CommandLineUtils.checkOptionDependencies(
logger,
commandLine,
"--rpc-ws-ssl-truststore-file",
rpcWsTrustStoreFile == null,
List.of("--rpc-ws-ssl-truststore-password"));
}

if (isRpcWsAuthenticationEnabled) {
CommandLineUtils.checkOptionDependencies(
Expand Down Expand Up @@ -222,6 +341,18 @@ public WebSocketConfiguration webSocketConfiguration(
webSocketConfiguration.setAuthenticationPublicKeyFile(rpcWsAuthenticationPublicKeyFile);
webSocketConfiguration.setAuthenticationAlgorithm(rpcWebsocketsAuthenticationAlgorithm);
webSocketConfiguration.setTimeoutSec(wsTimoutSec);
webSocketConfiguration.setSslEnabled(isRpcWsSslEnabled);
webSocketConfiguration.setKeyStorePath(rpcWsKeyStoreFile);
webSocketConfiguration.setKeyStorePassword(rpcWsKeyStorePassword);
webSocketConfiguration.setKeyStoreType(rpcWsKeyStoreType);
webSocketConfiguration.setClientAuthEnabled(isRpcWsClientAuthEnabled);
webSocketConfiguration.setTrustStorePath(rpcWsTrustStoreFile);
webSocketConfiguration.setTrustStorePassword(rpcWsTrustStorePassword);
webSocketConfiguration.setTrustStoreType(rpcWsTrustStoreType);
webSocketConfiguration.setKeyPath(rpcWsKeyFile);
webSocketConfiguration.setCertPath(rpcWsCertFile);
webSocketConfiguration.setTrustCertPath(rpcWsTrustCertFile);

return webSocketConfiguration;
}

Expand Down
13 changes: 13 additions & 0 deletions besu/src/test/resources/everything_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,19 @@ rpc-ws-max-frame-size=65535
rpc-ws-authentication-enabled=false
rpc-ws-authentication-credentials-file="none"
rpc-ws-authentication-jwt-public-key-file="none"
rpc-ws-ssl-enabled=false
rpc-ws-ssl-keystore-file="none.pfx"
rpc-ws-ssl-keystore-password="none.passwd"
rpc-ws-ssl-keystore-type="none"
rpc-ws-ssl-client-auth-enabled=false
rpc-ws-ssl-truststore-file="none.pfx"
rpc-ws-ssl-truststore-password="none.passwd"
rpc-ws-ssl-truststore-type="none"
rpc-ws-ssl-key-file="none.pfx"
rpc-ws-ssl-cert-file="none.pfx"
rpc-ws-ssl-trustcert-file="none.pfx"



# API
api-gas-price-blocks=100
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import com.google.common.base.MoreObjects;

Expand All @@ -49,6 +50,21 @@ public class WebSocketConfiguration {
private int maxActiveConnections;
private int maxFrameSize;

private boolean isSslEnabled = false;
private Optional<String> keyStorePath = Optional.empty();
private Optional<String> keyStorePassword = Optional.empty();
private Optional<String> keyStoreType = Optional.of("JKS"); // Default to JKS

private boolean clientAuthEnabled = false;
private Optional<String> trustStorePath = Optional.empty();
private Optional<String> trustStorePassword = Optional.empty();
private Optional<String> trustStoreType = Optional.of("JKS"); // Default to JKS

// For PEM format
private Optional<String> keyPath = Optional.empty();
private Optional<String> certPath = Optional.empty();
private Optional<String> trustCertPath = Optional.empty();

public static WebSocketConfiguration createDefault() {
final WebSocketConfiguration config = new WebSocketConfiguration();
config.setEnabled(false);
Expand Down Expand Up @@ -159,6 +175,102 @@ public void setTimeoutSec(final long timeoutSec) {
this.timeoutSec = timeoutSec;
}

public boolean isSslEnabled() {
return isSslEnabled;
}

public void setSslEnabled(final boolean isSslEnabled) {
this.isSslEnabled = isSslEnabled;
}

public Optional<String> getKeyStorePath() {
return keyStorePath;
}

public void setKeyStorePath(final String keyStorePath) {
this.keyStorePath = Optional.ofNullable(keyStorePath);
}

public Optional<String> getKeyStorePassword() {
return keyStorePassword;
}

public void setKeyStorePassword(final String keyStorePassword) {
this.keyStorePassword = Optional.ofNullable(keyStorePassword);
}

// Keystore Type
public Optional<String> getKeyStoreType() {
return keyStoreType;
}

public void setKeyStoreType(final String keyStoreType) {
this.keyStoreType = Optional.ofNullable(keyStoreType);
}

// Key Path (for PEM)
public Optional<String> getKeyPath() {
return keyPath;
}

public void setKeyPath(final String keyPath) {
this.keyPath = Optional.ofNullable(keyPath);
}

// Cert Path (for PEM)
public Optional<String> getCertPath() {
return certPath;
}

public void setCertPath(final String certPath) {
this.certPath = Optional.ofNullable(certPath);
}

// Client Authentication Enabled
public boolean isClientAuthEnabled() {
return clientAuthEnabled;
}

public void setClientAuthEnabled(final boolean clientAuthEnabled) {
this.clientAuthEnabled = clientAuthEnabled;
}

// Truststore Path
public Optional<String> getTrustStorePath() {
return trustStorePath;
}

public void setTrustStorePath(final String trustStorePath) {
this.trustStorePath = Optional.ofNullable(trustStorePath);
}

// Truststore Password
public Optional<String> getTrustStorePassword() {
return trustStorePassword;
}

public void setTrustStorePassword(final String trustStorePassword) {
this.trustStorePassword = Optional.ofNullable(trustStorePassword);
}

// Truststore Type
public Optional<String> getTrustStoreType() {
return trustStoreType;
}

public void setTrustStoreType(final String trustStoreType) {
this.trustStoreType = Optional.ofNullable(trustStoreType);
}

// Trust Cert Path (for PEM)
public Optional<String> getTrustCertPath() {
return trustCertPath;
}

public void setTrustCertPath(final String trustCertPath) {
this.trustCertPath = Optional.ofNullable(trustCertPath);
}

@Override
public boolean equals(final Object o) {
if (this == o) {
Expand Down
Loading
Loading