Skip to content

Commit

Permalink
p2p tls support (command line options and acceptance tests) (#2536)
Browse files Browse the repository at this point in the history
* p2p-tls AT keystores

generated using scripts from https://github.com/perusworld/besu-isolated-networks/blob/p2p-over-ssl/scripts/gen-at-keys.sh

Signed-off-by: Saravana Perumal Shanmugam <perusworld@linux.com>
  • Loading branch information
perusworld committed Jul 20, 2021
1 parent f347749 commit 7926f4a
Show file tree
Hide file tree
Showing 183 changed files with 3,918 additions and 17 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Expand Up @@ -14,5 +14,7 @@
*.ico binary
*.ttf binary
*.woff binary
*.p12 binary
*.db binary
*.woff2 binary
goss-linux-amd64 binary
1 change: 1 addition & 0 deletions acceptance-tests/dsl/build.gradle
Expand Up @@ -13,6 +13,7 @@ dependencies {
implementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts')
implementation project(':ethereum:eth')
implementation project(':ethereum:p2p')
implementation project(':pki')
implementation project(':ethereum:permissioning')
implementation project(':ethereum:rlp')
implementation project(':metrics:core')
Expand Down
Expand Up @@ -29,6 +29,7 @@
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition;
Expand Down Expand Up @@ -87,6 +88,7 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
private KeyPair keyPair;
private final Properties portsProperties = new Properties();
private final Boolean p2pEnabled;
private final Optional<TLSConfiguration> tlsConfiguration;
private final NetworkingConfiguration networkingConfiguration;
private final boolean revertReasonEnabled;

Expand Down Expand Up @@ -130,6 +132,7 @@ public BesuNode(
final NetworkName network,
final GenesisConfigurationProvider genesisConfigProvider,
final boolean p2pEnabled,
final Optional<TLSConfiguration> tlsConfiguration,
final NetworkingConfiguration networkingConfiguration,
final boolean discoveryEnabled,
final boolean bootnodeEligible,
Expand Down Expand Up @@ -169,6 +172,7 @@ public BesuNode(
this.devMode = devMode;
this.network = network;
this.p2pEnabled = p2pEnabled;
this.tlsConfiguration = tlsConfiguration;
this.networkingConfiguration = networkingConfiguration;
this.discoveryEnabled = discoveryEnabled;
this.bootnodeEligible = bootnodeEligible;
Expand Down Expand Up @@ -560,6 +564,10 @@ public boolean isP2pEnabled() {
return p2pEnabled;
}

public Optional<TLSConfiguration> getTLSConfiguration() {
return tlsConfiguration;
}

public NetworkingConfiguration getNetworkingConfiguration() {
return networkingConfiguration;
}
Expand Down
Expand Up @@ -20,6 +20,7 @@
import org.hyperledger.besu.cli.options.unstable.NetworkingOptions;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.plugin.services.metrics.MetricCategory;
Expand Down Expand Up @@ -246,6 +247,26 @@ public void startNode(final BesuNode node) {
final List<String> networkConfigParams =
NetworkingOptions.fromConfig(node.getNetworkingConfiguration()).getCLIOptions();
params.addAll(networkConfigParams);
if (node.getTLSConfiguration().isPresent()) {
final TLSConfiguration config = node.getTLSConfiguration().get();
params.add("--Xp2p-tls-enabled");
params.add("--Xp2p-tls-keystore-type");
params.add(config.getKeyStoreType());
params.add("--Xp2p-tls-keystore-file");
params.add(config.getKeyStorePath().toAbsolutePath().toString());
params.add("--Xp2p-tls-keystore-password-file");
params.add(config.getKeyStorePasswordPath().toAbsolutePath().toString());
params.add("--Xp2p-tls-crl-file");
params.add(config.getCrlPath().toAbsolutePath().toString());
if (null != config.getTrustStoreType()) {
params.add("--Xp2p-tls-truststore-type");
params.add(config.getTrustStoreType());
params.add("--Xp2p-tls-truststore-file");
params.add(config.getTrustStorePath().toAbsolutePath().toString());
params.add("--Xp2p-tls-truststore-password-file");
params.add(config.getTrustStorePasswordPath().toAbsolutePath().toString());
}
}
}

if (node.isRevertReasonEnabled()) {
Expand Down
Expand Up @@ -194,6 +194,7 @@ public void startNode(final BesuNode node) {
.permissioningService(new PermissioningServiceImpl())
.metricsConfiguration(node.getMetricsConfiguration())
.p2pEnabled(node.isP2pEnabled())
.p2pTLSConfiguration(node.getTLSConfiguration())
.graphQLConfiguration(GraphQLConfiguration.createDefault())
.staticNodes(
node.getStaticNodes().stream()
Expand Down
Expand Up @@ -163,11 +163,15 @@ private void startNode(final RunnableNode node, final boolean isBootNode) {
public void stop() {
// stops nodes but do not shutdown besuNodeRunner
for (final RunnableNode node : nodes.values()) {
if (node instanceof BesuNode) {
besuNodeRunner.stopNode((BesuNode) node); // besuNodeRunner.stopNode also calls node.stop
} else {
node.stop();
}
stopNode(node);
}
}

public void stopNode(final RunnableNode node) {
if (node instanceof BesuNode) {
besuNodeRunner.stopNode((BesuNode) node); // besuNodeRunner.stopNode also calls node.stop
} else {
node.stop();
}
}

Expand Down
Expand Up @@ -21,6 +21,7 @@
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationProvider;
Expand All @@ -42,6 +43,7 @@ public class BesuNodeConfiguration {
private final boolean devMode;
private final GenesisConfigurationProvider genesisConfigProvider;
private final boolean p2pEnabled;
private final Optional<TLSConfiguration> tlsConfiguration;
private final NetworkingConfiguration networkingConfiguration;
private final boolean discoveryEnabled;
private final boolean bootnodeEligible;
Expand Down Expand Up @@ -70,6 +72,7 @@ public class BesuNodeConfiguration {
final NetworkName network,
final GenesisConfigurationProvider genesisConfigProvider,
final boolean p2pEnabled,
final Optional<TLSConfiguration> tlsConfiguration,
final NetworkingConfiguration networkingConfiguration,
final boolean discoveryEnabled,
final boolean bootnodeEligible,
Expand All @@ -95,6 +98,7 @@ public class BesuNodeConfiguration {
this.network = network;
this.genesisConfigProvider = genesisConfigProvider;
this.p2pEnabled = p2pEnabled;
this.tlsConfiguration = tlsConfiguration;
this.networkingConfiguration = networkingConfiguration;
this.discoveryEnabled = discoveryEnabled;
this.bootnodeEligible = bootnodeEligible;
Expand Down Expand Up @@ -158,6 +162,10 @@ public boolean isP2pEnabled() {
return p2pEnabled;
}

public Optional<TLSConfiguration> getTLSConfiguration() {
return tlsConfiguration;
}

public NetworkingConfiguration getNetworkingConfiguration() {
return networkingConfiguration;
}
Expand Down
Expand Up @@ -22,23 +22,30 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration;
import org.hyperledger.besu.ethereum.api.tls.FileBasedPasswordProvider;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.MiningParametersTestBuilder;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper;
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationProvider;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import com.google.common.base.Charsets;

public class BesuNodeConfigurationBuilder {

private String name;
Expand All @@ -53,6 +60,7 @@ public class BesuNodeConfigurationBuilder {
private boolean devMode = true;
private GenesisConfigurationProvider genesisConfigProvider = ignore -> Optional.empty();
private Boolean p2pEnabled = true;
private Optional<TLSConfiguration> tlsConfiguration = Optional.empty();
private final NetworkingConfiguration networkingConfiguration = NetworkingConfiguration.create();
private boolean discoveryEnabled = true;
private boolean bootnodeEligible = true;
Expand Down Expand Up @@ -250,6 +258,91 @@ public BesuNodeConfigurationBuilder p2pEnabled(final Boolean p2pEnabled) {
return this;
}

private static Path toPath(final String path) throws Exception {
return Path.of(BesuNodeConfigurationBuilder.class.getResource(path).toURI());
}

public BesuNodeConfigurationBuilder p2pTLSEnabled(final String name, final String type) {
final TLSConfiguration.Builder builder = TLSConfiguration.Builder.tlsConfiguration();
try {
final String nsspin = "/p2p-tls/%s/nsspin.txt";
final String truststore = "/p2p-tls/%s/truststore.jks";
final String crl = "/p2p-tls/%s/crl.pem";
switch (type) {
case KeyStoreWrapper.KEYSTORE_TYPE_JKS:
builder
.withKeyStoreType(type)
.withKeyStorePath(toPath(String.format("/p2p-tls/%s/keystore.jks", name)))
.withKeyStorePasswordSupplier(
new FileBasedPasswordProvider(toPath(String.format(nsspin, name))))
.withKeyStorePasswordPath(toPath(String.format(nsspin, name)))
.withTrustStoreType(type)
.withTrustStorePath(toPath(String.format(truststore, name)))
.withTrustStorePasswordSupplier(
new FileBasedPasswordProvider(toPath(String.format(nsspin, name))))
.withTrustStorePasswordPath(toPath(String.format(nsspin, name)))
.withCrlPath(toPath(String.format(crl, name)));
break;
case KeyStoreWrapper.KEYSTORE_TYPE_PKCS12:
builder
.withKeyStoreType(type)
.withKeyStorePath(toPath(String.format("/p2p-tls/%s/keys.p12", name)))
.withKeyStorePasswordSupplier(
new FileBasedPasswordProvider(toPath(String.format(nsspin, name))))
.withKeyStorePasswordPath(toPath(String.format(nsspin, name)))
.withTrustStoreType(KeyStoreWrapper.KEYSTORE_TYPE_JKS)
.withTrustStorePath(toPath(String.format(truststore, name)))
.withTrustStorePasswordSupplier(
new FileBasedPasswordProvider(toPath(String.format(nsspin, name))))
.withTrustStorePasswordPath(toPath(String.format(nsspin, name)))
.withCrlPath(toPath(String.format(crl, name)));
break;
case KeyStoreWrapper.KEYSTORE_TYPE_PKCS11:
builder
.withKeyStoreType(type)
.withKeyStorePath(
initNSSConfigFile(toPath(String.format("/p2p-tls/%s/nss.cfg", name))))
.withKeyStorePasswordSupplier(
new FileBasedPasswordProvider(toPath(String.format(nsspin, name))))
.withKeyStorePasswordPath(toPath(String.format(nsspin, name)))
.withCrlPath(toPath(String.format(crl, name)));
break;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
this.tlsConfiguration = Optional.of(builder.build());
return this;
}

private Path initNSSConfigFile(final Path srcFilePath) {
Path ret = null;
try {
final String content = Files.readString(srcFilePath);
final String updated =
content.replaceAll(
"(nssSecmodDirectory\\W*)(\\.\\/.*)",
"$1".concat(srcFilePath.toAbsolutePath().toString().replace("nss.cfg", "nssdb")));
final Path targetFilePath = createTemporaryFile("nsscfg");
Files.write(targetFilePath, updated.getBytes(Charsets.UTF_8));
ret = targetFilePath;
} catch (IOException e) {
throw new RuntimeException("Error populating nss config file", e);
}
return ret;
}

private Path createTemporaryFile(final String suffix) {
final File tempFile;
try {
tempFile = File.createTempFile("temp", suffix);
tempFile.deleteOnExit();
} catch (IOException e) {
throw new RuntimeException("Error creating temporary file", e);
}
return tempFile.toPath();
}

public BesuNodeConfigurationBuilder discoveryEnabled(final boolean discoveryEnabled) {
this.discoveryEnabled = discoveryEnabled;
return this;
Expand Down Expand Up @@ -321,6 +414,7 @@ public BesuNodeConfiguration build() {
network,
genesisConfigProvider,
p2pEnabled,
tlsConfiguration,
networkingConfiguration,
discoveryEnabled,
bootnodeEligible,
Expand Down
Expand Up @@ -29,6 +29,7 @@
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.node.RunnableNode;
Expand Down Expand Up @@ -65,6 +66,7 @@ public BesuNode create(final BesuNodeConfiguration config) throws IOException {
config.getNetwork(),
config.getGenesisConfigProvider(),
config.isP2pEnabled(),
config.getTLSConfiguration(),
config.getNetworkingConfiguration(),
config.isDiscoveryEnabled(),
config.isBootnodeEligible(),
Expand Down Expand Up @@ -346,6 +348,31 @@ public BesuNode createIbft2Node(final String name) throws IOException {
.build());
}

public BesuNode createIbft2NodeWithTLS(final String name, final String type) throws IOException {
return create(
new BesuNodeConfigurationBuilder()
.name(name)
.miningEnabled()
.p2pTLSEnabled(name, type)
.jsonRpcConfiguration(node.createJsonRpcWithIbft2EnabledConfig(false))
.webSocketConfiguration(node.createWebSocketEnabledConfig())
.devMode(false)
.genesisConfigProvider(genesis::createIbft2GenesisConfig)
.build());
}

public BesuNode createIbft2NodeWithTLSJKS(final String name) throws IOException {
return createIbft2NodeWithTLS(name, KeyStoreWrapper.KEYSTORE_TYPE_JKS);
}

public BesuNode createIbft2NodeWithTLSPKCS12(final String name) throws IOException {
return createIbft2NodeWithTLS(name, KeyStoreWrapper.KEYSTORE_TYPE_PKCS12);
}

public BesuNode createIbft2NodeWithTLSPKCS11(final String name) throws IOException {
return createIbft2NodeWithTLS(name, KeyStoreWrapper.KEYSTORE_TYPE_PKCS11);
}

public BesuNode createQbftNode(final String name) throws IOException {
return create(
new BesuNodeConfigurationBuilder()
Expand Down Expand Up @@ -420,6 +447,39 @@ public BesuNode createIbft2NodeWithValidators(final String name, final String...
.build());
}

public BesuNode createIbft2TLSNodeWithValidators(
final String name, final String type, final String... validators) throws IOException {

return create(
new BesuNodeConfigurationBuilder()
.name(name)
.miningEnabled()
.p2pTLSEnabled(name, type)
.jsonRpcConfiguration(node.createJsonRpcWithIbft2EnabledConfig(false))
.webSocketConfiguration(node.createWebSocketEnabledConfig())
.devMode(false)
.genesisConfigProvider(
nodes ->
node.createGenesisConfigForValidators(
asList(validators), nodes, genesis::createIbft2GenesisConfig))
.build());
}

public BesuNode createIbft2TLSJKSNodeWithValidators(final String name, final String... validators)
throws IOException {
return createIbft2TLSNodeWithValidators(name, KeyStoreWrapper.KEYSTORE_TYPE_JKS, validators);
}

public BesuNode createIbft2TLSPKCS12NodeWithValidators(
final String name, final String... validators) throws IOException {
return createIbft2TLSNodeWithValidators(name, KeyStoreWrapper.KEYSTORE_TYPE_PKCS12, validators);
}

public BesuNode createIbft2TLSPKCS11NodeWithValidators(
final String name, final String... validators) throws IOException {
return createIbft2TLSNodeWithValidators(name, KeyStoreWrapper.KEYSTORE_TYPE_PKCS11, validators);
}

public BesuNode createQbftNodeWithValidators(final String name, final String... validators)
throws IOException {

Expand Down

0 comments on commit 7926f4a

Please sign in to comment.