PKI Block Creation cli configuration (#2619)

* Added CLI options for PKI Block Creation
* BesuCommand changes for PKI Block Creation

Signed-off-by: Lucas Saldanha <lucascrsaldanha@gmail.com>
pull/2623/head
Lucas Saldanha 3 years ago committed by GitHub
parent b9e1ce05c0
commit 047b680ddc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      besu/build.gradle
  2. 21
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  3. 144
      besu/src/main/java/org/hyperledger/besu/cli/options/unstable/PkiBlockCreationOptions.java
  4. 9
      besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java
  5. 13
      besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java
  6. 71
      besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
  7. 23
      besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java
  8. 46
      consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/pki/PkiBlockCreationConfiguration.java
  9. 91
      consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/pki/PkiBlockCreationConfigurationProvider.java
  10. 11
      consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/pki/PkiQbftContext.java
  11. 71
      consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/pki/PkiBlockCreationConfigurationProviderTest.java
  12. 29
      pki/src/main/java/org/hyperledger/besu/pki/config/PkiKeyStoreConfiguration.java

@ -90,4 +90,5 @@ dependencies {
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.awaitility:awaitility'
testImplementation 'org.mockito:mockito-core'
testImplementation 'commons-io:commons-io'
}

@ -59,6 +59,7 @@ import org.hyperledger.besu.cli.options.unstable.MiningOptions;
import org.hyperledger.besu.cli.options.unstable.NatOptions;
import org.hyperledger.besu.cli.options.unstable.NativeLibraryOptions;
import org.hyperledger.besu.cli.options.unstable.NetworkingOptions;
import org.hyperledger.besu.cli.options.unstable.PkiBlockCreationOptions;
import org.hyperledger.besu.cli.options.unstable.PrivacyPluginOptions;
import org.hyperledger.besu.cli.options.unstable.RPCOptions;
import org.hyperledger.besu.cli.options.unstable.SynchronizerOptions;
@ -78,6 +79,8 @@ import org.hyperledger.besu.cli.util.VersionProvider;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.config.GoQuorumOptions;
import org.hyperledger.besu.consensus.qbft.pki.PkiBlockCreationConfiguration;
import org.hyperledger.besu.consensus.qbft.pki.PkiBlockCreationConfigurationProvider;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.controller.BesuControllerBuilder;
import org.hyperledger.besu.controller.TargetingGasLimitCalculator;
@ -286,6 +289,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
new PreSynchronizationTaskRunner();
private final Set<Integer> allocatedPorts = new HashSet<>();
private final PkiBlockCreationConfigurationProvider pkiBlockCreationConfigProvider;
// CLI options defined by user at runtime.
// Options parsing is done with CLI library Picocli https://picocli.info/
@ -1097,6 +1101,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
@Mixin private P2PTLSConfigOptions p2pTLSConfigOptions;
@Mixin private PkiBlockCreationOptions pkiBlockCreationOptions;
private EthNetworkConfig ethNetworkConfig;
private JsonRpcConfiguration jsonRpcConfiguration;
private GraphQLConfiguration graphQLConfiguration;
@ -1136,7 +1142,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
new StorageServiceImpl(),
new SecurityModuleServiceImpl(),
new PermissioningServiceImpl(),
new PrivacyPluginServiceImpl());
new PrivacyPluginServiceImpl(),
new PkiBlockCreationConfigurationProvider());
}
@VisibleForTesting
@ -1152,7 +1159,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
final StorageServiceImpl storageService,
final SecurityModuleServiceImpl securityModuleService,
final PermissioningServiceImpl permissioningService,
final PrivacyPluginServiceImpl privacyPluginPluginService) {
final PrivacyPluginServiceImpl privacyPluginPluginService,
final PkiBlockCreationConfigurationProvider pkiBlockCreationConfigProvider) {
this.logger = logger;
this.rlpBlockImporter = rlpBlockImporter;
this.rlpBlockExporterFactory = rlpBlockExporterFactory;
@ -1167,6 +1175,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
this.privacyPluginPluginService = privacyPluginPluginService;
pluginCommonConfiguration = new BesuCommandConfigurationService();
besuPluginContext.addService(BesuConfiguration.class, pluginCommonConfiguration);
this.pkiBlockCreationConfigProvider = pkiBlockCreationConfigProvider;
}
public void parse(
@ -1441,6 +1450,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
validateNetStatsParams();
validateDnsOptionsParams();
p2pTLSConfigOptions.checkP2PTLSOptionsDependencies(logger, commandLine);
pkiBlockCreationOptions.checkPkiBlockCreationOptionsDependencies(logger, commandLine);
}
@SuppressWarnings("ConstantConditions")
@ -1711,6 +1721,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.metricsSystem(metricsSystem.get())
.messagePermissioningProviders(permissioningService.getMessagePermissioningProviders())
.privacyParameters(privacyParameters(storageProvider))
.pkiBlockCreationConfiguration(maybePkiBlockCreationConfiguration())
.clock(Clock.systemUTC())
.isRevertReasonEnabled(isRevertReasonEnabled)
.storageProvider(storageProvider)
@ -2269,6 +2280,12 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
return this.keyValueStorageProvider;
}
private Optional<PkiBlockCreationConfiguration> maybePkiBlockCreationConfiguration() {
return pkiBlockCreationOptions
.asDomainConfig(commandLine)
.map(pkiBlockCreationConfigProvider::load);
}
private SynchronizerConfiguration buildSyncConfig() {
return unstableSynchronizerOptions
.toDomainObject()

@ -0,0 +1,144 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.unstable;
import static java.util.Arrays.asList;
import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP;
import org.hyperledger.besu.cli.util.CommandLineUtils;
import org.hyperledger.besu.ethereum.api.tls.FileBasedPasswordProvider;
import org.hyperledger.besu.pki.config.PkiKeyStoreConfiguration;
import java.nio.file.Path;
import java.util.Optional;
import org.apache.logging.log4j.Logger;
import picocli.CommandLine;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParameterException;
public class PkiBlockCreationOptions {
@Option(
names = {"--Xpki-block-creation-enabled"},
hidden = true,
description = "Enable PKI integration (default: ${DEFAULT-VALUE})")
Boolean enabled = false;
@Option(
names = {"--Xpki-block-creation-keystore-type"},
hidden = true,
paramLabel = "<NAME>",
description = "PKI service keystore type. Required if PKI Block Creation is enabled.")
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"})
String keyStoreType = PkiKeyStoreConfiguration.DEFAULT_KEYSTORE_TYPE;
@Option(
names = {"--Xpki-block-creation-keystore-file"},
hidden = true,
paramLabel = MANDATORY_FILE_FORMAT_HELP,
description = "Keystore containing key/certificate for PKI Block Creation.")
Path keyStoreFile = null;
@Option(
names = {"--Xpki-block-creation-keystore-password-file"},
hidden = true,
paramLabel = MANDATORY_FILE_FORMAT_HELP,
description =
"File containing password to unlock keystore for PKI Integration. Required if PKI Block Creation is enabled.")
Path keyStorePasswordFile = null;
@Option(
names = {"--Xpki-block-creation-keystore-certificate-alias"},
hidden = true,
paramLabel = "<NAME>",
description =
"Alias of the certificate that will be included in the blocks proposed by this validator.")
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"})
String certificateAlias = PkiKeyStoreConfiguration.DEFAULT_CERTIFICATE_ALIAS;
@Option(
names = {"--Xpki-block-creation-truststore-type"},
hidden = true,
paramLabel = "<NAME>",
description = "PKI Integration truststore type.")
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"})
String trustStoreType = PkiKeyStoreConfiguration.DEFAULT_KEYSTORE_TYPE;
@Option(
names = {"--Xpki-block-creation-truststore-file"},
hidden = true,
paramLabel = MANDATORY_FILE_FORMAT_HELP,
description = "Truststore containing trusted certificates for PKI Block Creation.")
Path trustStoreFile = null;
@Option(
names = {"--Xpki-block-creation-truststore-password-file"},
hidden = true,
paramLabel = MANDATORY_FILE_FORMAT_HELP,
description = "File containing password to unlock truststore for PKI Block Creation.")
Path trustStorePasswordFile = null;
@Option(
names = {"--Xpki-block-creation-crl-file"},
hidden = true,
paramLabel = MANDATORY_FILE_FORMAT_HELP,
description = "File with all CRLs for PKI Block Creation.")
Path crlFile = null;
public Optional<PkiKeyStoreConfiguration> asDomainConfig(final CommandLine commandLine) {
if (!enabled) {
return Optional.empty();
}
if (keyStoreFile == null) {
throw new ParameterException(
commandLine, "KeyStore file is required when PKI Block Creation is enabled");
}
if (keyStorePasswordFile == null) {
throw new ParameterException(
commandLine,
"File containing password to unlock keystore is required when PKI Block Creation is enabled");
}
return Optional.of(
new PkiKeyStoreConfiguration.Builder()
.withKeyStoreType(keyStoreType)
.withKeyStorePath(keyStoreFile)
.withKeyStorePasswordSupplier(new FileBasedPasswordProvider(keyStorePasswordFile))
.withCertificateAlias(certificateAlias)
.withTrustStoreType(trustStoreType)
.withTrustStorePath(trustStoreFile)
.withTrustStorePasswordSupplier(
null == trustStorePasswordFile
? null
: new FileBasedPasswordProvider(trustStorePasswordFile))
.withCrlFilePath(crlFile)
.build());
}
public void checkPkiBlockCreationOptionsDependencies(
final Logger logger, final CommandLine commandLine) {
CommandLineUtils.checkOptionDependencies(
logger,
commandLine,
"--Xpki-block-creation-enabled",
!enabled,
asList(
"--Xpki-block-creation-keystore-file", "--Xpki-block-creation-keystore-password-file"));
}
}

@ -17,6 +17,7 @@ package org.hyperledger.besu.controller;
import static com.google.common.base.Preconditions.checkNotNull;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.consensus.qbft.pki.PkiBlockCreationConfiguration;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods;
@ -91,6 +92,8 @@ public abstract class BesuControllerBuilder {
protected MiningParameters miningParameters;
protected ObservableMetricsSystem metricsSystem;
protected PrivacyParameters privacyParameters;
protected Optional<PkiBlockCreationConfiguration> pkiBlockCreationConfiguration =
Optional.empty();
protected Path dataDirectory;
protected Clock clock;
protected NodeKey nodeKey;
@ -160,6 +163,12 @@ public abstract class BesuControllerBuilder {
return this;
}
public BesuControllerBuilder pkiBlockCreationConfiguration(
final Optional<PkiBlockCreationConfiguration> pkiBlockCreationConfiguration) {
this.pkiBlockCreationConfiguration = pkiBlockCreationConfiguration;
return this;
}
public BesuControllerBuilder dataDirectory(final Path dataDirectory) {
this.dataDirectory = dataDirectory;
return this;

@ -73,13 +73,11 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.p2p.config.SubProtocolConfiguration;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper;
import org.hyperledger.besu.util.Subscribers;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@ -93,14 +91,12 @@ public class QbftBesuControllerBuilder extends BftBesuControllerBuilder {
private BftEventQueue bftEventQueue;
private QbftConfigOptions qbftConfig;
private ValidatorPeers peers;
// TODO initialize this in BesuCommand as part of the PKI setup (will be done in a follow up PR)
private final Optional<KeyStoreWrapper> pkiKeyStore = Optional.empty();
@Override
protected Supplier<BftExtraDataCodec> bftExtraDataCodec() {
return Suppliers.memoize(
() -> {
if (pkiKeyStore.isPresent()) {
if (pkiBlockCreationConfiguration.isPresent()) {
return new PkiQbftExtraDataCodec();
} else {
return new QbftExtraDataCodec();
@ -295,9 +291,12 @@ public class QbftBesuControllerBuilder extends BftBesuControllerBuilder {
validatorProvider = new TransactionValidatorProvider(blockchain, validatorContractController);
}
if (pkiKeyStore.isPresent()) {
if (pkiBlockCreationConfiguration.isPresent()) {
return new PkiQbftContext(
validatorProvider, epochManager, bftBlockInterface().get(), pkiKeyStore.get());
validatorProvider,
epochManager,
bftBlockInterface().get(),
pkiBlockCreationConfiguration.get());
} else {
return new BftContext(validatorProvider, epochManager, bftBlockInterface().get());
}

@ -75,6 +75,7 @@ import org.hyperledger.besu.ethereum.worldstate.PrunerConfiguration;
import org.hyperledger.besu.metrics.StandardMetricCategory;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.nat.NatMethod;
import org.hyperledger.besu.pki.config.PkiKeyStoreConfiguration;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.util.number.Fraction;
import org.hyperledger.besu.util.number.Percentage;
@ -99,6 +100,7 @@ import java.util.stream.Stream;
import com.google.common.collect.Lists;
import com.google.common.io.Resources;
import io.vertx.core.json.JsonObject;
import org.apache.commons.io.FileUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.logging.log4j.Level;
import org.apache.tuweni.bytes.Bytes;
@ -4312,4 +4314,73 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(AbstractAltBnPrecompiledContract.isNative()).isTrue();
verify(mockLogger).info("Using LibEthPairings native alt bn128");
}
@Test
public void pkiBlockCreationIsDisabledByDefault() {
parseCommand();
verifyNoInteractions(mockPkiBlockCreationConfigProvider);
}
@Test
public void pkiBlockCreationKeyStoreFileRequired() {
parseCommand(
"--Xpki-block-creation-enabled",
"--Xpki-block-creation-keystore-password-file",
"/tmp/pwd");
assertThat(commandErrorOutput.toString())
.contains("KeyStore file is required when PKI Block Creation is enabled");
}
@Test
public void pkiBlockCreationPasswordFileRequired() {
parseCommand(
"--Xpki-block-creation-enabled", "--Xpki-block-creation-keystore-file", "/tmp/keystore");
assertThat(commandErrorOutput.toString())
.contains(
"File containing password to unlock keystore is required when PKI Block Creation is enabled");
}
@Rule public TemporaryFolder pkiTempFolder = new TemporaryFolder();
@Test
public void pkiBlockCreationFullConfig() throws Exception {
// Create temp file with password
final File pwdFile = pkiTempFolder.newFile("pwd");
FileUtils.writeStringToFile(pwdFile, "foo", UTF_8);
parseCommand(
"--Xpki-block-creation-enabled",
"--Xpki-block-creation-keystore-type",
"JKS",
"--Xpki-block-creation-keystore-file",
"/tmp/keystore",
"--Xpki-block-creation-keystore-password-file",
pwdFile.getAbsolutePath(),
"--Xpki-block-creation-keystore-certificate-alias",
"anAlias",
"--Xpki-block-creation-truststore-type",
"JKS",
"--Xpki-block-creation-truststore-file",
"/tmp/truststore",
"--Xpki-block-creation-truststore-password-file",
pwdFile.getAbsolutePath(),
"--Xpki-block-creation-crl-file",
"/tmp/crl");
final PkiKeyStoreConfiguration pkiKeyStoreConfig =
pkiKeyStoreConfigurationArgumentCaptor.getValue();
assertThat(pkiKeyStoreConfig).isNotNull();
assertThat(pkiKeyStoreConfig.getKeyStoreType()).isEqualTo("JKS");
assertThat(pkiKeyStoreConfig.getKeyStorePath()).isEqualTo(Path.of("/tmp/keystore"));
assertThat(pkiKeyStoreConfig.getKeyStorePassword()).isEqualTo("foo");
assertThat(pkiKeyStoreConfig.getCertificateAlias()).isEqualTo("anAlias");
assertThat(pkiKeyStoreConfig.getTrustStoreType()).isEqualTo("JKS");
assertThat(pkiKeyStoreConfig.getTrustStorePath()).isEqualTo(Path.of("/tmp/truststore"));
assertThat(pkiKeyStoreConfig.getTrustStorePassword()).isEqualTo("foo");
assertThat(pkiKeyStoreConfig.getCrlFilePath()).hasValue(Path.of("/tmp/crl"));
}
}

@ -37,6 +37,8 @@ import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions;
import org.hyperledger.besu.cli.options.unstable.NetworkingOptions;
import org.hyperledger.besu.cli.options.unstable.SynchronizerOptions;
import org.hyperledger.besu.cli.options.unstable.TransactionPoolOptions;
import org.hyperledger.besu.consensus.qbft.pki.PkiBlockCreationConfiguration;
import org.hyperledger.besu.consensus.qbft.pki.PkiBlockCreationConfigurationProvider;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.controller.BesuControllerBuilder;
import org.hyperledger.besu.controller.NoopPluginServiceFactory;
@ -62,6 +64,7 @@ import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.pki.config.PkiKeyStoreConfiguration;
import org.hyperledger.besu.plugin.services.BesuConfiguration;
import org.hyperledger.besu.plugin.services.PicoCLIOptions;
import org.hyperledger.besu.plugin.services.StorageService;
@ -156,6 +159,9 @@ public abstract class CommandTestAbstract {
@Mock
protected Logger mockLogger;
@Mock protected PkiBlockCreationConfigurationProvider mockPkiBlockCreationConfigProvider;
@Mock protected PkiBlockCreationConfiguration mockPkiBlockCreationConfiguration;
@Captor protected ArgumentCaptor<Collection<Bytes>> bytesCollectionCollector;
@Captor protected ArgumentCaptor<Path> pathArgumentCaptor;
@Captor protected ArgumentCaptor<String> stringArgumentCaptor;
@ -170,6 +176,7 @@ public abstract class CommandTestAbstract {
@Captor protected ArgumentCaptor<StorageProvider> storageProviderArgumentCaptor;
@Captor protected ArgumentCaptor<EthProtocolConfiguration> ethProtocolConfigurationArgumentCaptor;
@Captor protected ArgumentCaptor<DataStorageConfiguration> dataStorageConfigurationArgumentCaptor;
@Captor protected ArgumentCaptor<PkiKeyStoreConfiguration> pkiKeyStoreConfigurationArgumentCaptor;
@Captor
protected ArgumentCaptor<Optional<PermissioningConfiguration>>
@ -196,6 +203,8 @@ public abstract class CommandTestAbstract {
when(mockControllerBuilder.messagePermissioningProviders(any()))
.thenReturn(mockControllerBuilder);
when(mockControllerBuilder.privacyParameters(any())).thenReturn(mockControllerBuilder);
when(mockControllerBuilder.pkiBlockCreationConfiguration(any()))
.thenReturn(mockControllerBuilder);
when(mockControllerBuilder.clock(any())).thenReturn(mockControllerBuilder);
when(mockControllerBuilder.isRevertReasonEnabled(false)).thenReturn(mockControllerBuilder);
when(mockControllerBuilder.storageProvider(any())).thenReturn(mockControllerBuilder);
@ -286,6 +295,11 @@ public abstract class CommandTestAbstract {
lenient()
.when(mockBesuPluginContext.getService(StorageService.class))
.thenReturn(Optional.of(storageService));
lenient()
.doReturn(mockPkiBlockCreationConfiguration)
.when(mockPkiBlockCreationConfigProvider)
.load(pkiKeyStoreConfigurationArgumentCaptor.capture());
}
// Display outputs for debug purpose
@ -335,7 +349,8 @@ public abstract class CommandTestAbstract {
mockBesuPluginContext,
environment,
storageService,
securityModuleService);
securityModuleService,
mockPkiBlockCreationConfigProvider);
besuCommands.add(besuCommand);
besuCommand.setBesuConfiguration(commonPluginConfiguration);
@ -369,7 +384,8 @@ public abstract class CommandTestAbstract {
final BesuPluginContextImpl besuPluginContext,
final Map<String, String> environment,
final StorageServiceImpl storageService,
final SecurityModuleServiceImpl securityModuleService) {
final SecurityModuleServiceImpl securityModuleService,
final PkiBlockCreationConfigurationProvider pkiBlockCreationConfigProvider) {
super(
mockLogger,
mockBlockImporter,
@ -382,7 +398,8 @@ public abstract class CommandTestAbstract {
storageService,
securityModuleService,
new PermissioningServiceImpl(),
new PrivacyPluginServiceImpl());
new PrivacyPluginServiceImpl(),
pkiBlockCreationConfigProvider);
this.mockNodeKey = mockNodeKey;
this.keyPair = keyPair;
}

@ -0,0 +1,46 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.consensus.qbft.pki;
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper;
public class PkiBlockCreationConfiguration {
private final KeyStoreWrapper keyStore;
private final KeyStoreWrapper trustStore;
private final String certificateAlias;
public PkiBlockCreationConfiguration(
final KeyStoreWrapper keyStore,
final KeyStoreWrapper trustStore,
final String certificateAlias) {
this.keyStore = keyStore;
this.trustStore = trustStore;
this.certificateAlias = certificateAlias;
}
public KeyStoreWrapper getKeyStore() {
return keyStore;
}
public KeyStoreWrapper getTrustStore() {
return trustStore;
}
public String getCertificateAlias() {
return certificateAlias;
}
}

@ -0,0 +1,91 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.consensus.qbft.pki;
import static com.google.common.base.Preconditions.checkNotNull;
import org.hyperledger.besu.pki.config.PkiKeyStoreConfiguration;
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper;
import org.hyperledger.besu.pki.keystore.SoftwareKeyStoreWrapper;
import java.nio.file.Path;
import com.google.common.annotations.VisibleForTesting;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class PkiBlockCreationConfigurationProvider {
private static final Logger LOG = LogManager.getLogger();
private final KeyStoreWrapperProvider keyStoreWrapperProvider;
public PkiBlockCreationConfigurationProvider() {
this(SoftwareKeyStoreWrapper::new);
}
@VisibleForTesting
PkiBlockCreationConfigurationProvider(final KeyStoreWrapperProvider keyStoreWrapperProvider) {
this.keyStoreWrapperProvider = checkNotNull(keyStoreWrapperProvider);
}
public PkiBlockCreationConfiguration load(
final PkiKeyStoreConfiguration pkiKeyStoreConfiguration) {
KeyStoreWrapper keyStore;
try {
keyStore =
keyStoreWrapperProvider.apply(
pkiKeyStoreConfiguration.getKeyStoreType(),
pkiKeyStoreConfiguration.getKeyStorePath(),
pkiKeyStoreConfiguration.getKeyStorePassword(),
null);
LOG.info("Loaded PKI Block Creation KeyStore {}", pkiKeyStoreConfiguration.getKeyStorePath());
} catch (Exception e) {
final String message = "Error loading PKI Block Creation KeyStore";
LOG.error(message, e);
throw new RuntimeException(message, e);
}
KeyStoreWrapper trustStore;
try {
trustStore =
keyStoreWrapperProvider.apply(
pkiKeyStoreConfiguration.getTrustStoreType(),
pkiKeyStoreConfiguration.getTrustStorePath(),
pkiKeyStoreConfiguration.getTrustStorePassword(),
pkiKeyStoreConfiguration.getCrlFilePath().orElse(null));
LOG.info(
"Loaded PKI Block Creation TrustStore {}", pkiKeyStoreConfiguration.getTrustStorePath());
} catch (Exception e) {
final String message = "Error loading PKI Block Creation TrustStore";
LOG.error(message, e);
throw new RuntimeException(message, e);
}
return new PkiBlockCreationConfiguration(
keyStore, trustStore, pkiKeyStoreConfiguration.getCertificateAlias());
}
@FunctionalInterface
interface KeyStoreWrapperProvider {
KeyStoreWrapper apply(
final String keyStoreType,
final Path keyStorePath,
final String keyStorePassword,
final Path crl);
}
}

@ -19,22 +19,21 @@ import org.hyperledger.besu.consensus.common.EpochManager;
import org.hyperledger.besu.consensus.common.bft.BftBlockInterface;
import org.hyperledger.besu.consensus.common.bft.BftContext;
import org.hyperledger.besu.consensus.common.validator.ValidatorProvider;
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper;
public class PkiQbftContext extends BftContext {
private final KeyStoreWrapper keyStoreWrapper;
private final PkiBlockCreationConfiguration pkiBlockCreationConfiguration;
public PkiQbftContext(
final ValidatorProvider validatorProvider,
final EpochManager epochManager,
final BftBlockInterface blockInterface,
final KeyStoreWrapper keyStoreWrapper) {
final PkiBlockCreationConfiguration pkiBlockCreationConfiguration) {
super(validatorProvider, epochManager, blockInterface);
this.keyStoreWrapper = keyStoreWrapper;
this.pkiBlockCreationConfiguration = pkiBlockCreationConfiguration;
}
public KeyStoreWrapper getKeyStoreWrapper() {
return keyStoreWrapper;
public PkiBlockCreationConfiguration getPkiBlockCreationConfiguration() {
return pkiBlockCreationConfiguration;
}
}

@ -0,0 +1,71 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.consensus.qbft.pki;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.consensus.qbft.pki.PkiBlockCreationConfigurationProvider.KeyStoreWrapperProvider;
import org.hyperledger.besu.pki.config.PkiKeyStoreConfiguration;
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper;
import java.nio.file.Path;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class PkiBlockCreationConfigurationProviderTest {
@Mock KeyStoreWrapperProvider keyStoreWrapperProvider;
@Mock KeyStoreWrapper keyStoreWrapper;
@Mock KeyStoreWrapper trustStoreWrapper;
@Test
public void pkiBlockCreationConfigurationIsLoadedCorrectly() {
when(keyStoreWrapperProvider.apply(any(), eq(Path.of("/tmp/keystore")), eq("pwd"), isNull()))
.thenReturn(keyStoreWrapper);
when(keyStoreWrapperProvider.apply(
any(), eq(Path.of("/tmp/truststore")), eq("pwd"), eq(Path.of("/tmp/crl"))))
.thenReturn(trustStoreWrapper);
final PkiKeyStoreConfiguration pkiKeyStoreConfiguration =
new PkiKeyStoreConfiguration.Builder()
.withKeyStorePath(Path.of("/tmp/keystore"))
.withKeyStorePasswordSupplier(() -> "pwd")
.withTrustStorePath(Path.of("/tmp/truststore"))
.withTrustStorePasswordSupplier(() -> "pwd")
.withCertificateAlias("anAlias")
.withCrlFilePath(Path.of("/tmp/crl"))
.build();
final PkiBlockCreationConfigurationProvider pkiBlockCreationConfigProvider =
new PkiBlockCreationConfigurationProvider(keyStoreWrapperProvider);
final PkiBlockCreationConfiguration pkiBlockCreationConfiguration =
pkiBlockCreationConfigProvider.load(pkiKeyStoreConfiguration);
assertThat(pkiBlockCreationConfiguration).isNotNull();
assertThat(pkiBlockCreationConfiguration.getKeyStore()).isNotNull();
assertThat(pkiBlockCreationConfiguration.getTrustStore()).isNotNull();
assertThat(pkiBlockCreationConfiguration.getCertificateAlias()).isEqualTo("anAlias");
}
}

@ -12,14 +12,15 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.pki;
package org.hyperledger.besu.pki.config;
import static java.util.Objects.requireNonNull;
import java.nio.file.Path;
import java.util.Optional;
import java.util.function.Supplier;
public class PkiConfiguration {
public class PkiKeyStoreConfiguration {
public static String DEFAULT_KEYSTORE_TYPE = "PKCS12";
public static String DEFAULT_CERTIFICATE_ALIAS = "validator";
@ -31,15 +32,17 @@ public class PkiConfiguration {
private final String trustStoreType;
private final Path trustStorePath;
private final Supplier<String> trustStorePasswordSupplier;
private final Optional<Path> crlFilePath;
public PkiConfiguration(
public PkiKeyStoreConfiguration(
final String keyStoreType,
final Path keyStorePath,
final Supplier<String> keyStorePasswordSupplier,
final String certificateAlias,
final String trustStoreType,
final Path trustStorePath,
final Supplier<String> trustStorePasswordSupplier) {
final Supplier<String> trustStorePasswordSupplier,
final Optional<Path> crlFilePath) {
this.keyStoreType = keyStoreType;
this.keyStorePath = keyStorePath;
this.keyStorePasswordSupplier = keyStorePasswordSupplier;
@ -47,6 +50,7 @@ public class PkiConfiguration {
this.trustStoreType = trustStoreType;
this.trustStorePath = trustStorePath;
this.trustStorePasswordSupplier = trustStorePasswordSupplier;
this.crlFilePath = crlFilePath;
}
public String getKeyStoreType() {
@ -77,6 +81,10 @@ public class PkiConfiguration {
return trustStorePasswordSupplier.get();
}
public Optional<Path> getCrlFilePath() {
return crlFilePath;
}
public static final class Builder {
private String keyStoreType = DEFAULT_KEYSTORE_TYPE;
@ -86,6 +94,7 @@ public class PkiConfiguration {
private String trustStoreType = DEFAULT_KEYSTORE_TYPE;
private Path trustStorePath;
private Supplier<String> trustStorePasswordSupplier;
private Path crlFilePath;
public Builder() {}
@ -125,17 +134,23 @@ public class PkiConfiguration {
return this;
}
public PkiConfiguration build() {
public Builder withCrlFilePath(final Path filePath) {
this.crlFilePath = filePath;
return this;
}
public PkiKeyStoreConfiguration build() {
requireNonNull(keyStoreType, "Key Store Type must not be null");
requireNonNull(keyStorePasswordSupplier, "Key Store password supplier must not be null");
return new PkiConfiguration(
return new PkiKeyStoreConfiguration(
keyStoreType,
keyStorePath,
keyStorePasswordSupplier,
certificateAlias,
trustStoreType,
trustStorePath,
trustStorePasswordSupplier);
trustStorePasswordSupplier,
Optional.ofNullable(crlFilePath));
}
}
}
Loading…
Cancel
Save