mirror of
https://github.com/vacp2p/status-linea-besu.git
synced 2026-01-09 23:38:08 -05:00
Add RPC WS options to specify password file for keystore and truststore (#7970)
* Add RPC WS options to specify password file for keystore and truststore Signed-off-by: Bhanu Pulluri <bhanu.pulluri@kaleido.io> * update changelog Signed-off-by: Bhanu Pulluri <bhanu.pulluri@kaleido.io> --------- Signed-off-by: Bhanu Pulluri <bhanu.pulluri@kaleido.io> Signed-off-by: Bhanu Pulluri <59369753+pullurib@users.noreply.github.com> Co-authored-by: Bhanu Pulluri <bhanu.pulluri@kaleido.io> Co-authored-by: Fabio Di Fabio <fabio.difabio@consensys.net>
This commit is contained in:
@@ -43,9 +43,11 @@
|
||||
- Add a method to check if a metric category is enabled to the plugin API [#7832](https://github.com/hyperledger/besu/pull/7832)
|
||||
- Add a new metric collector for counters which get their value from suppliers [#7894](https://github.com/hyperledger/besu/pull/7894)
|
||||
- Add account and state overrides to `eth_call` [#7801](https://github.com/hyperledger/besu/pull/7801) and `eth_estimateGas` [#7890](https://github.com/hyperledger/besu/pull/7890)
|
||||
- Add RPC WS options to specify password file for keystore and truststore [#7970](https://github.com/hyperledger/besu/pull/7970)
|
||||
- Prometheus Java Metrics library upgraded to version 1.3.3 [#7880](https://github.com/hyperledger/besu/pull/7880)
|
||||
- Add histogram to Prometheus metrics system [#7944](https://github.com/hyperledger/besu/pull/7944)
|
||||
|
||||
|
||||
### Bug fixes
|
||||
- Fix registering new metric categories from plugins [#7825](https://github.com/hyperledger/besu/pull/7825)
|
||||
- Fix CVE-2024-47535 [7878](https://github.com/hyperledger/besu/pull/7878)
|
||||
|
||||
@@ -37,6 +37,35 @@ import picocli.CommandLine;
|
||||
|
||||
/** This class represents the WebSocket options for the RPC. */
|
||||
public class RpcWebsocketOptions {
|
||||
|
||||
static class KeystorePasswordOptions {
|
||||
@CommandLine.Option(
|
||||
names = {"--rpc-ws-ssl-keystore-password"},
|
||||
paramLabel = "<PASSWORD>",
|
||||
description = "Password for the WebSocket RPC keystore file")
|
||||
private String rpcWsKeyStorePassword;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {"--rpc-ws-ssl-keystore-password-file"},
|
||||
paramLabel = "<FILE>",
|
||||
description = "File containing the password for WebSocket keystore.")
|
||||
private String rpcWsKeystorePasswordFile;
|
||||
}
|
||||
|
||||
static class TruststorePasswordOptions {
|
||||
@CommandLine.Option(
|
||||
names = {"--rpc-ws-ssl-truststore-password"},
|
||||
paramLabel = "<PASSWORD>",
|
||||
description = "Password for the WebSocket RPC truststore file")
|
||||
private String rpcWsTrustStorePassword;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {"--rpc-ws-ssl-truststore-password-file"},
|
||||
paramLabel = "<FILE>",
|
||||
description = "File containing the password for WebSocket truststore.")
|
||||
private String rpcWsTruststorePasswordFile;
|
||||
}
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {"--rpc-ws-authentication-jwt-algorithm"},
|
||||
description =
|
||||
@@ -131,12 +160,6 @@ public class RpcWebsocketOptions {
|
||||
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,
|
||||
@@ -167,12 +190,6 @@ public class RpcWebsocketOptions {
|
||||
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,
|
||||
@@ -185,6 +202,12 @@ public class RpcWebsocketOptions {
|
||||
description = "Type of the truststore (JKS, PKCS12, PEM)")
|
||||
private String rpcWsTrustStoreType = null;
|
||||
|
||||
@CommandLine.ArgGroup(exclusive = true, multiplicity = "1")
|
||||
private KeystorePasswordOptions keystorePasswordOptions;
|
||||
|
||||
@CommandLine.ArgGroup(exclusive = true, multiplicity = "1")
|
||||
private TruststorePasswordOptions truststorePasswordOptions;
|
||||
|
||||
/** Default Constructor. */
|
||||
public RpcWebsocketOptions() {}
|
||||
|
||||
@@ -292,7 +315,7 @@ public class RpcWebsocketOptions {
|
||||
commandLine,
|
||||
"--rpc-ws-ssl-keystore-file",
|
||||
rpcWsKeyStoreFile == null,
|
||||
List.of("--rpc-ws-ssl-keystore-password"));
|
||||
List.of("--rpc-ws-ssl-keystore-password", "--rpc-ws-ssl-keystore-password-file"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +325,7 @@ public class RpcWebsocketOptions {
|
||||
commandLine,
|
||||
"--rpc-ws-ssl-truststore-file",
|
||||
rpcWsTrustStoreFile == null,
|
||||
List.of("--rpc-ws-ssl-truststore-password"));
|
||||
List.of("--rpc-ws-ssl-truststore-password", "--rpc-ws-ssl-truststore-password-file"));
|
||||
}
|
||||
|
||||
if (isRpcWsAuthenticationEnabled) {
|
||||
@@ -343,16 +366,27 @@ public class RpcWebsocketOptions {
|
||||
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);
|
||||
|
||||
if (keystorePasswordOptions != null) {
|
||||
webSocketConfiguration.setKeyStorePassword(keystorePasswordOptions.rpcWsKeyStorePassword);
|
||||
webSocketConfiguration.setKeyStorePasswordFile(
|
||||
keystorePasswordOptions.rpcWsKeystorePasswordFile);
|
||||
}
|
||||
|
||||
if (truststorePasswordOptions != null) {
|
||||
webSocketConfiguration.setTrustStorePassword(
|
||||
truststorePasswordOptions.rpcWsTrustStorePassword);
|
||||
webSocketConfiguration.setTrustStorePasswordFile(
|
||||
truststorePasswordOptions.rpcWsTruststorePasswordFile);
|
||||
}
|
||||
|
||||
return webSocketConfiguration;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,10 +123,12 @@ 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-password-file="none.txt"
|
||||
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-password-file="none.txt"
|
||||
rpc-ws-ssl-truststore-type="none"
|
||||
rpc-ws-ssl-key-file="none.pfx"
|
||||
rpc-ws-ssl-cert-file="none.pfx"
|
||||
|
||||
@@ -20,6 +20,10 @@ import org.hyperledger.besu.ethereum.api.handlers.TimeoutOptions;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.JwtAlgorithm;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -54,11 +58,13 @@ public class WebSocketConfiguration {
|
||||
private Optional<String> keyStorePath = Optional.empty();
|
||||
private Optional<String> keyStorePassword = Optional.empty();
|
||||
private Optional<String> keyStoreType = Optional.of("JKS"); // Default to JKS
|
||||
private Optional<String> keyStorePasswordFile = Optional.empty();
|
||||
|
||||
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
|
||||
private Optional<String> trustStorePasswordFile = Optional.empty();
|
||||
|
||||
// For PEM format
|
||||
private Optional<String> keyPath = Optional.empty();
|
||||
@@ -191,8 +197,11 @@ public class WebSocketConfiguration {
|
||||
this.keyStorePath = Optional.ofNullable(keyStorePath);
|
||||
}
|
||||
|
||||
public Optional<String> getKeyStorePassword() {
|
||||
return keyStorePassword;
|
||||
public Optional<String> getKeyStorePassword() throws IOException {
|
||||
if (keyStorePassword.isPresent()) {
|
||||
return keyStorePassword;
|
||||
}
|
||||
return Optional.ofNullable(getKeystorePasswordFromFile());
|
||||
}
|
||||
|
||||
public void setKeyStorePassword(final String keyStorePassword) {
|
||||
@@ -245,8 +254,11 @@ public class WebSocketConfiguration {
|
||||
}
|
||||
|
||||
// Truststore Password
|
||||
public Optional<String> getTrustStorePassword() {
|
||||
return trustStorePassword;
|
||||
public Optional<String> getTrustStorePassword() throws IOException {
|
||||
if (trustStorePassword.isPresent()) {
|
||||
return trustStorePassword;
|
||||
}
|
||||
return Optional.ofNullable(getTruststorePasswordFromFile());
|
||||
}
|
||||
|
||||
public void setTrustStorePassword(final String trustStorePassword) {
|
||||
@@ -258,6 +270,38 @@ public class WebSocketConfiguration {
|
||||
return trustStoreType;
|
||||
}
|
||||
|
||||
public void setKeyStorePasswordFile(final String keyStorePasswordFile) {
|
||||
this.keyStorePasswordFile = Optional.ofNullable(keyStorePasswordFile);
|
||||
}
|
||||
|
||||
public void setTrustStorePasswordFile(final String trustStorePasswordFile) {
|
||||
this.trustStorePasswordFile = Optional.ofNullable(trustStorePasswordFile);
|
||||
}
|
||||
|
||||
private String loadPasswordFromFile(final String passwordFile) throws IOException {
|
||||
if (passwordFile != null) {
|
||||
Path path = Path.of(passwordFile);
|
||||
if (Files.exists(path)) {
|
||||
return Files.readString(path, StandardCharsets.UTF_8).trim();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getKeystorePasswordFromFile() throws IOException {
|
||||
if (keyStorePasswordFile.isPresent()) {
|
||||
return loadPasswordFromFile(keyStorePasswordFile.get());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getTruststorePasswordFromFile() throws IOException {
|
||||
if (trustStorePasswordFile.isPresent()) {
|
||||
return loadPasswordFromFile(trustStorePasswordFile.get());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setTrustStoreType(final String trustStoreType) {
|
||||
this.trustStoreType = Optional.ofNullable(trustStoreType);
|
||||
}
|
||||
|
||||
@@ -122,9 +122,16 @@ public class WebSocketService {
|
||||
// Check if SSL/TLS is enabled in the configuration
|
||||
if (configuration.isSslEnabled()) {
|
||||
serverOptions.setSsl(true);
|
||||
String keystorePassword = null;
|
||||
|
||||
String keystorePath = configuration.getKeyStorePath().orElse(null);
|
||||
String keystorePassword = configuration.getKeyStorePassword().orElse(null);
|
||||
try {
|
||||
keystorePassword = configuration.getKeyStorePassword().orElse(null);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error reading keystore password", e);
|
||||
resultFuture.completeExceptionally(e);
|
||||
return resultFuture;
|
||||
}
|
||||
String keyPath = configuration.getKeyPath().orElse(null);
|
||||
String certPath = configuration.getCertPath().orElse(null);
|
||||
|
||||
@@ -146,9 +153,16 @@ public class WebSocketService {
|
||||
// Set up truststore for client authentication (mTLS)
|
||||
if (configuration.isClientAuthEnabled()) {
|
||||
serverOptions.setClientAuth(ClientAuth.REQUIRED);
|
||||
String truststorePassword;
|
||||
|
||||
String truststorePath = configuration.getTrustStorePath().orElse(null);
|
||||
String truststorePassword = configuration.getTrustStorePassword().orElse("");
|
||||
try {
|
||||
truststorePassword = configuration.getTrustStorePassword().orElse(null);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error reading truststore password", e);
|
||||
resultFuture.completeExceptionally(e);
|
||||
return resultFuture;
|
||||
}
|
||||
String truststoreType = configuration.getTrustStoreType().orElse("JKS");
|
||||
String trustCertPath = configuration.getTrustCertPath().orElse(null);
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.security.KeyStore;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
@@ -390,14 +393,20 @@ public class WebSocketServiceTLSTest {
|
||||
clientTrustStore.store(fos, "password".toCharArray());
|
||||
}
|
||||
|
||||
File tempFile = File.createTempFile("pwdfile", ".txt");
|
||||
tempFile.deleteOnExit();
|
||||
try (Writer writer = Files.newBufferedWriter(tempFile.toPath(), Charset.defaultCharset())) {
|
||||
writer.write("password");
|
||||
}
|
||||
|
||||
// Configure WebSocket with SSL and client authentication enabled
|
||||
config.setSslEnabled(true);
|
||||
config.setKeyStorePath(serverKeystoreFile.getAbsolutePath());
|
||||
config.setKeyStorePassword("password");
|
||||
config.setKeyStorePasswordFile(tempFile.getAbsolutePath());
|
||||
config.setKeyStoreType("PKCS12");
|
||||
config.setClientAuthEnabled(true);
|
||||
config.setTrustStorePath(serverTruststoreFile.getAbsolutePath());
|
||||
config.setTrustStorePassword("password");
|
||||
config.setTrustStorePasswordFile(tempFile.getAbsolutePath());
|
||||
config.setTrustStoreType("PKCS12");
|
||||
|
||||
// Create and start WebSocketService
|
||||
|
||||
Reference in New Issue
Block a user