Remove P2P TLS (experimental) feature (#7942)

pull/7964/head
Sally MacFarlane 5 days ago committed by GitHub
parent 792c6569cd
commit 63496dbc6c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 2
      acceptance-tests/dsl/build.gradle
  3. 8
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java
  4. 21
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java
  5. 1
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java
  6. 8
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfiguration.java
  7. 66
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java
  8. 18
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java
  9. 60
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/pki/PKCS11Utils.java
  10. 1
      besu/build.gradle
  11. 27
      besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java
  12. 12
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  13. 163
      besu/src/main/java/org/hyperledger/besu/cli/options/P2PTLSConfigOptions.java
  14. 11
      besu/src/test/resources/everything_config.toml
  15. 1
      ethereum/p2p/build.gradle
  16. 9
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java
  17. 29
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java
  18. 159
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/NettyTLSConnectionInitializer.java
  19. 197
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/TLSConfiguration.java
  20. 230
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/TLSContextFactory.java
  21. 2
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java
  22. 156
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PPlainNetworkTest.java
  23. 195
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/NettyTLSConnectionInitializerTest.java
  24. 504
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/TLSContextFactoryTest.java
  25. 49
      pki/build.gradle
  26. 54
      pki/src/main/java/org/hyperledger/besu/pki/PkiException.java
  27. 142
      pki/src/main/java/org/hyperledger/besu/pki/cms/CmsCreator.java
  28. 203
      pki/src/main/java/org/hyperledger/besu/pki/cms/CmsValidator.java
  29. 303
      pki/src/main/java/org/hyperledger/besu/pki/config/PkiKeyStoreConfiguration.java
  30. 53
      pki/src/main/java/org/hyperledger/besu/pki/crl/CRLUtil.java
  31. 68
      pki/src/main/java/org/hyperledger/besu/pki/keystore/AbstractKeyStoreWrapper.java
  32. 210
      pki/src/main/java/org/hyperledger/besu/pki/keystore/HardwareKeyStoreWrapper.java
  33. 88
      pki/src/main/java/org/hyperledger/besu/pki/keystore/KeyStoreWrapper.java
  34. 269
      pki/src/main/java/org/hyperledger/besu/pki/keystore/SoftwareKeyStoreWrapper.java
  35. 217
      pki/src/test/java/org/hyperledger/besu/pki/util/TestCertificateUtils.java
  36. 27
      pki/src/test/resources/keystore/invalidpartner1client1/crl.pem
  37. BIN
      pki/src/test/resources/keystore/invalidpartner1client1/keys.p12
  38. BIN
      pki/src/test/resources/keystore/invalidpartner1client1/keystore.jks
  39. 6
      pki/src/test/resources/keystore/invalidpartner1client1/nss.cfg
  40. BIN
      pki/src/test/resources/keystore/invalidpartner1client1/nssdb/cert8.db
  41. BIN
      pki/src/test/resources/keystore/invalidpartner1client1/nssdb/key3.db
  42. BIN
      pki/src/test/resources/keystore/invalidpartner1client1/nssdb/secmod.db
  43. 1
      pki/src/test/resources/keystore/invalidpartner1client1/nsspin.txt
  44. 72
      pki/src/test/resources/keystore/invalidpartner1client1/ssl-ca.pem
  45. 129
      pki/src/test/resources/keystore/invalidpartner1client1/ssl.pem
  46. BIN
      pki/src/test/resources/keystore/invalidpartner1client1/truststore.jks
  47. BIN
      pki/src/test/resources/keystore/keystore
  48. 27
      pki/src/test/resources/keystore/partner1client1/crl.pem
  49. BIN
      pki/src/test/resources/keystore/partner1client1/nssdb/cert8.db
  50. BIN
      pki/src/test/resources/keystore/partner1client1/nssdb/key3.db
  51. BIN
      pki/src/test/resources/keystore/partner1client1/nssdb/secmod.db
  52. 1
      pki/src/test/resources/keystore/partner1client1/nsspin.txt
  53. 70
      pki/src/test/resources/keystore/partner1client1/ssl-ca.pem
  54. 126
      pki/src/test/resources/keystore/partner1client1/ssl.pem
  55. 27
      pki/src/test/resources/keystore/partner2client1/crl.pem
  56. BIN
      pki/src/test/resources/keystore/partner2client1/keys.p12
  57. BIN
      pki/src/test/resources/keystore/partner2client1/keystore.jks
  58. 6
      pki/src/test/resources/keystore/partner2client1/nss.cfg
  59. BIN
      pki/src/test/resources/keystore/partner2client1/nssdb/cert8.db
  60. BIN
      pki/src/test/resources/keystore/partner2client1/nssdb/key3.db
  61. BIN
      pki/src/test/resources/keystore/partner2client1/nssdb/secmod.db
  62. 1
      pki/src/test/resources/keystore/partner2client1/nsspin.txt
  63. 70
      pki/src/test/resources/keystore/partner2client1/ssl-ca.pem
  64. 126
      pki/src/test/resources/keystore/partner2client1/ssl.pem
  65. BIN
      pki/src/test/resources/keystore/partner2client1/truststore.jks
  66. BIN
      pki/src/test/resources/keystore/truststore
  67. 1
      pki/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
  68. 1
      settings.gradle

@ -4,6 +4,7 @@
### Breaking Changes
- Removed Retesteth rpc service and commands [#7833](https://github.com/hyperledger/besu/pull/7783)
- TLS for P2P (early access feature) has been removed [#7942](https://github.com/hyperledger/besu/pull/7942)
- With the upgrade of the Prometheus Java Metrics library, there are the following changes:
- Gauge names are not allowed to end with `total`, therefore the metric `besu_blockchain_difficulty_total` is losing the `_total` suffix
- The `_created` timestamps are not returned by default, you can set the env var `BESU_OPTS="-Dio.prometheus.exporter.includeCreatedTimestamps=true"` to enable them

@ -18,8 +18,6 @@ dependencies {
implementation project(':ethereum:permissioning')
implementation project(':ethereum:rlp')
implementation project(':metrics:core')
implementation project(':pki')
implementation project(path: ':pki', configuration: 'testArtifacts')
implementation project(':plugin-api')
implementation project(':plugins:rocksdb')
implementation project(':services:kvstore')

@ -32,7 +32,6 @@ import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
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.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
@ -96,7 +95,6 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
private final Properties portsProperties = new Properties();
private final Boolean p2pEnabled;
private final int p2pPort;
private final Optional<TLSConfiguration> tlsConfiguration;
private final NetworkingConfiguration networkingConfiguration;
private final boolean revertReasonEnabled;
@ -156,7 +154,6 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
final GenesisConfigurationProvider genesisConfigProvider,
final boolean p2pEnabled,
final int p2pPort,
final Optional<TLSConfiguration> tlsConfiguration,
final NetworkingConfiguration networkingConfiguration,
final boolean discoveryEnabled,
final boolean bootnodeEligible,
@ -207,7 +204,6 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
this.network = network;
this.p2pEnabled = p2pEnabled;
this.p2pPort = p2pPort;
this.tlsConfiguration = tlsConfiguration;
this.networkingConfiguration = networkingConfiguration;
this.discoveryEnabled = discoveryEnabled;
this.bootnodeEligible = bootnodeEligible;
@ -659,10 +655,6 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
return p2pEnabled;
}
public Optional<TLSConfiguration> getTLSConfiguration() {
return tlsConfiguration;
}
public NetworkingConfiguration getNetworkingConfiguration() {
return networkingConfiguration;
}

@ -22,7 +22,6 @@ import org.hyperledger.besu.cli.options.TransactionPoolOptions;
import org.hyperledger.besu.cli.options.storage.DataStorageOptions;
import org.hyperledger.besu.ethereum.api.jsonrpc.ipc.JsonRpcIpcConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
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;
@ -365,26 +364,6 @@ public class ProcessBesuNodeRunner implements BesuNodeRunner {
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()) {

@ -197,7 +197,6 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
.permissioningService(permissioningService)
.metricsConfiguration(node.getMetricsConfiguration())
.p2pEnabled(node.isP2pEnabled())
.p2pTLSConfiguration(node.getTLSConfiguration())
.graphQLConfiguration(GraphQLConfiguration.createDefault())
.staticNodes(node.getStaticNodes().stream().map(EnodeURLImpl::fromString).toList())
.besuPluginContext(besuPluginContext)

@ -25,7 +25,6 @@ import org.hyperledger.besu.ethereum.core.MiningConfiguration;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
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.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
@ -56,7 +55,6 @@ public class BesuNodeConfiguration {
private final GenesisConfigurationProvider genesisConfigProvider;
private final boolean p2pEnabled;
private final int p2pPort;
private final Optional<TLSConfiguration> tlsConfiguration;
private final NetworkingConfiguration networkingConfiguration;
private final boolean discoveryEnabled;
private final boolean bootnodeEligible;
@ -95,7 +93,6 @@ public class BesuNodeConfiguration {
final GenesisConfigurationProvider genesisConfigProvider,
final boolean p2pEnabled,
final int p2pPort,
final Optional<TLSConfiguration> tlsConfiguration,
final NetworkingConfiguration networkingConfiguration,
final boolean discoveryEnabled,
final boolean bootnodeEligible,
@ -131,7 +128,6 @@ public class BesuNodeConfiguration {
this.genesisConfigProvider = genesisConfigProvider;
this.p2pEnabled = p2pEnabled;
this.p2pPort = p2pPort;
this.tlsConfiguration = tlsConfiguration;
this.networkingConfiguration = networkingConfiguration;
this.discoveryEnabled = discoveryEnabled;
this.bootnodeEligible = bootnodeEligible;
@ -226,10 +222,6 @@ public class BesuNodeConfiguration {
return p2pPort;
}
public Optional<TLSConfiguration> getTLSConfiguration() {
return tlsConfiguration;
}
public NetworkingConfiguration getNetworkingConfiguration() {
return networkingConfiguration;
}

@ -16,9 +16,6 @@ package org.hyperledger.besu.tests.acceptance.dsl.node.configuration;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Collections.singletonList;
import static org.hyperledger.besu.pki.keystore.KeyStoreWrapper.KEYSTORE_TYPE_JKS;
import static org.hyperledger.besu.pki.keystore.KeyStoreWrapper.KEYSTORE_TYPE_PKCS11;
import static org.hyperledger.besu.pki.keystore.KeyStoreWrapper.KEYSTORE_TYPE_PKCS12;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.crypto.KeyPair;
@ -31,7 +28,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis;
import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.JwtAlgorithm;
import org.hyperledger.besu.ethereum.api.jsonrpc.ipc.JsonRpcIpcConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration;
import org.hyperledger.besu.ethereum.api.tls.FileBasedPasswordProvider;
import org.hyperledger.besu.ethereum.core.AddressHelpers;
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration;
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration.MutableInitValues;
@ -39,12 +35,10 @@ import org.hyperledger.besu.ethereum.core.MiningConfiguration;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
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.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationProvider;
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.pki.PKCS11Utils;
import java.io.File;
import java.net.URISyntaxException;
@ -84,7 +78,6 @@ public class BesuNodeConfigurationBuilder {
private GenesisConfigurationProvider genesisConfigProvider = ignore -> Optional.empty();
private Boolean p2pEnabled = true;
private int p2pPort = 0;
private Optional<TLSConfiguration> tlsConfiguration = Optional.empty();
private final NetworkingConfiguration networkingConfiguration = NetworkingConfiguration.create();
private boolean discoveryEnabled = true;
private boolean bootnodeEligible = true;
@ -381,64 +374,6 @@ public class BesuNodeConfigurationBuilder {
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 = "/pki-certs/%s/nsspin.txt";
final String truststore = "/pki-certs/%s/truststore.p12";
final String crl = "/pki-certs/crl/crl.pem";
switch (type) {
case KEYSTORE_TYPE_JKS:
builder
.withKeyStoreType(type)
.withKeyStorePath(toPath(String.format("/pki-certs/%s/%<s.jks", name)))
.withKeyStorePasswordSupplier(
new FileBasedPasswordProvider(toPath(String.format(nsspin, name))))
.withKeyStorePasswordPath(toPath(String.format(nsspin, name)))
.withTrustStoreType(KEYSTORE_TYPE_PKCS12)
.withTrustStorePath(toPath(String.format(truststore, name)))
.withTrustStorePasswordSupplier(
new FileBasedPasswordProvider(toPath(String.format(nsspin, name))))
.withTrustStorePasswordPath(toPath(String.format(nsspin, name)))
.withCrlPath(toPath(crl));
break;
case KEYSTORE_TYPE_PKCS12:
builder
.withKeyStoreType(type)
.withKeyStorePath(toPath(String.format("/pki-certs/%s/%<s.p12", name)))
.withKeyStorePasswordSupplier(
new FileBasedPasswordProvider(toPath(String.format(nsspin, name))))
.withKeyStorePasswordPath(toPath(String.format(nsspin, name)))
.withTrustStoreType(KEYSTORE_TYPE_PKCS12)
.withTrustStorePath(toPath(String.format(truststore, name)))
.withTrustStorePasswordSupplier(
new FileBasedPasswordProvider(toPath(String.format(nsspin, name))))
.withTrustStorePasswordPath(toPath(String.format(nsspin, name)))
.withCrlPath(toPath(crl));
break;
case KEYSTORE_TYPE_PKCS11:
builder
.withKeyStoreType(type)
.withKeyStorePath(
PKCS11Utils.initNSSConfigFile(
toPath(String.format("/pki-certs/%s/nss.cfg", name))))
.withKeyStorePasswordSupplier(
new FileBasedPasswordProvider(toPath(String.format(nsspin, name))))
.withKeyStorePasswordPath(toPath(String.format(nsspin, name)))
.withCrlPath(toPath(crl));
break;
}
} catch (final Exception e) {
throw new RuntimeException(e);
}
this.tlsConfiguration = Optional.of(builder.build());
return this;
}
public BesuNodeConfigurationBuilder discoveryEnabled(final boolean discoveryEnabled) {
this.discoveryEnabled = discoveryEnabled;
return this;
@ -545,7 +480,6 @@ public class BesuNodeConfigurationBuilder {
genesisConfigProvider,
p2pEnabled,
p2pPort,
tlsConfiguration,
networkingConfiguration,
discoveryEnabled,
bootnodeEligible,

@ -25,7 +25,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguratio
import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
@ -69,7 +68,6 @@ public class BesuNodeFactory {
config.getGenesisConfigProvider(),
config.isP2pEnabled(),
config.getP2pPort(),
config.getTLSConfiguration(),
config.getNetworkingConfiguration(),
config.isDiscoveryEnabled(),
config.isBootnodeEligible(),
@ -583,7 +581,6 @@ public class BesuNodeFactory {
new BesuNodeConfigurationBuilder()
.name(name)
.miningEnabled()
.p2pTLSEnabled(name, type)
.jsonRpcConfiguration(node.createJsonRpcWithIbft2EnabledConfig(false))
.webSocketConfiguration(node.createWebSocketEnabledConfig())
.devMode(false)
@ -596,21 +593,6 @@ public class BesuNodeFactory {
.build());
}
public BesuNode createQbftTLSJKSNodeWithValidators(final String name, final String... validators)
throws IOException {
return createQbftTLSNodeWithValidators(name, KeyStoreWrapper.KEYSTORE_TYPE_JKS, validators);
}
public BesuNode createQbftTLSPKCS12NodeWithValidators(
final String name, final String... validators) throws IOException {
return createQbftTLSNodeWithValidators(name, KeyStoreWrapper.KEYSTORE_TYPE_PKCS12, validators);
}
public BesuNode createQbftTLSPKCS11NodeWithValidators(
final String name, final String... validators) throws IOException {
return createQbftTLSNodeWithValidators(name, KeyStoreWrapper.KEYSTORE_TYPE_PKCS11, validators);
}
public BesuNode createQbftNodeWithValidators(final String name, final String... validators)
throws IOException {

@ -1,60 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.tests.acceptance.dsl.node.configuration.pki;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.Properties;
public class PKCS11Utils {
public static Path initNSSConfigFile(final Path srcFilePath) {
// load nss file as Properties
final Properties nssProp = new Properties();
try (InputStream input = new FileInputStream(srcFilePath.toFile())) {
nssProp.load(input);
String nssDbPath = srcFilePath.getParent().resolve("nssdb").toAbsolutePath().toString();
nssProp.setProperty("nssSecmodDirectory", nssDbPath);
} catch (final IOException e) {
throw new UncheckedIOException(e);
}
// store modified config into temporary file
final Path targetFilePath = createTemporaryFile("nsscfg");
try (FileOutputStream outputStream = new FileOutputStream(targetFilePath.toFile())) {
nssProp.store(outputStream, null);
} catch (final IOException e) {
throw new UncheckedIOException(e);
}
return targetFilePath;
}
private static 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();
}
}

@ -34,7 +34,6 @@ dependencies {
api 'org.slf4j:slf4j-api'
implementation project(':config')
implementation project(':pki')
implementation project(':consensus:clique')
implementation project(':consensus:common')
implementation project(':consensus:ibft')

@ -92,7 +92,6 @@ import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration;
import org.hyperledger.besu.ethereum.p2p.permissions.PeerPermissionSubnet;
import org.hyperledger.besu.ethereum.p2p.permissions.PeerPermissions;
import org.hyperledger.besu.ethereum.p2p.permissions.PeerPermissionsDenylist;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.SubProtocol;
import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController;
@ -165,7 +164,6 @@ public class RunnerBuilder {
private NetworkingConfiguration networkingConfiguration = NetworkingConfiguration.create();
private final Collection<Bytes> bannedNodeIds = new ArrayList<>();
private boolean p2pEnabled = true;
private Optional<TLSConfiguration> p2pTLSConfiguration = Optional.empty();
private boolean discovery;
private String p2pAdvertisedHost;
private String p2pListenInterface = NetworkUtility.INADDR_ANY;
@ -235,30 +233,6 @@ public class RunnerBuilder {
return this;
}
/**
* TLSConfiguration p2pTLSConfiguration.
*
* @param p2pTLSConfiguration the TLSConfiguration p2pTLSConfiguration
* @return the runner builder
*/
public RunnerBuilder p2pTLSConfiguration(final TLSConfiguration p2pTLSConfiguration) {
this.p2pTLSConfiguration = Optional.of(p2pTLSConfiguration);
return this;
}
/**
* Optional TLSConfiguration p2pTLSConfiguration.
*
* @param p2pTLSConfiguration the TLSConfiguration p2pTLSConfiguration
* @return the runner builder
*/
public RunnerBuilder p2pTLSConfiguration(final Optional<TLSConfiguration> p2pTLSConfiguration) {
if (null != p2pTLSConfiguration) {
this.p2pTLSConfiguration = p2pTLSConfiguration;
}
return this;
}
/**
* Enable Discovery.
*
@ -735,7 +709,6 @@ public class RunnerBuilder {
.supportedCapabilities(caps)
.natService(natService)
.storageProvider(storageProvider)
.p2pTLSConfiguration(p2pTLSConfiguration)
.blockchain(context.getBlockchain())
.blockNumberForks(besuController.getGenesisConfigOptions().getForkBlockNumbers())
.timestampForks(besuController.getGenesisConfigOptions().getForkBlockTimestamps())

@ -60,7 +60,6 @@ import org.hyperledger.besu.cli.options.NativeLibraryOptions;
import org.hyperledger.besu.cli.options.NetworkingOptions;
import org.hyperledger.besu.cli.options.NodePrivateKeyFileOption;
import org.hyperledger.besu.cli.options.P2PDiscoveryOptions;
import org.hyperledger.besu.cli.options.P2PTLSConfigOptions;
import org.hyperledger.besu.cli.options.PermissionsOptions;
import org.hyperledger.besu.cli.options.PluginsConfigurationOptions;
import org.hyperledger.besu.cli.options.PrivacyPluginOptions;
@ -127,7 +126,6 @@ import org.hyperledger.besu.ethereum.p2p.discovery.P2PDiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.p2p.peers.StaticNodesParser;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
import org.hyperledger.besu.ethereum.privacy.storage.keyvalue.PrivacyKeyValueStorageProvider;
@ -259,7 +257,6 @@ import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.ExecutionException;
import picocli.CommandLine.IExecutionStrategy;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParameterException;
@ -704,8 +701,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
description = "Specifies the number of last blocks to cache (default: ${DEFAULT-VALUE})")
private final Integer numberOfblocksToCache = 0;
@Mixin private P2PTLSConfigOptions p2pTLSConfigOptions;
// Plugins Configuration Option Group
@CommandLine.ArgGroup(validate = false)
PluginsConfigurationOptions pluginsConfigurationOptions = new PluginsConfigurationOptions();
@ -720,7 +715,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private ApiConfiguration apiConfiguration;
private MetricsConfiguration metricsConfiguration;
private Optional<PermissioningConfiguration> permissioningConfiguration;
private Optional<TLSConfiguration> p2pTLSConfiguration;
private DataStorageConfiguration dataStorageConfiguration;
private Collection<EnodeURL> staticNodes;
private BesuController besuController;
@ -1232,7 +1226,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
return synchronize(
besuController,
p2PDiscoveryConfig.p2pEnabled(),
p2pTLSConfiguration,
p2PDiscoveryConfig.peerDiscoveryEnabled(),
ethNetworkConfig,
p2PDiscoveryConfig.p2pHost(),
@ -1457,7 +1450,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
validateApiOptions();
validateConsensusSyncCompatibilityOptions();
validatePluginOptions();
p2pTLSConfigOptions.checkP2PTLSOptionsDependencies(logger, commandLine);
}
private void validateConsensusSyncCompatibilityOptions() {
@ -1696,7 +1688,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
if (isEngineApiEnabled()) {
engineJsonRpcConfiguration = createEngineJsonRpcConfiguration();
}
p2pTLSConfiguration = p2pTLSConfigOptions.p2pTLSConfiguration(commandLine);
graphQLConfiguration =
graphQlOptions.graphQLConfiguration(
hostsAllowlist, p2PDiscoveryOptions.p2pHost, unstableRPCOptions.getHttpTimeoutSec());
@ -2221,7 +2212,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private Runner synchronize(
final BesuController controller,
final boolean p2pEnabled,
final Optional<TLSConfiguration> p2pTLSConfiguration,
final boolean peerDiscoveryEnabled,
final EthNetworkConfig ethNetworkConfig,
final String p2pAdvertisedHost,
@ -2241,8 +2231,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
checkNotNull(runnerBuilder);
p2pTLSConfiguration.ifPresent(runnerBuilder::p2pTLSConfiguration);
final Runner runner =
runnerBuilder
.vertx(vertx)

@ -1,163 +0,0 @@
/*
* 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;
import static java.util.Arrays.asList;
import static org.hyperledger.besu.cli.DefaultCommandValues.DEFAULT_KEYSTORE_TYPE;
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.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
import java.nio.file.Path;
import java.util.Optional;
import org.slf4j.Logger;
import picocli.CommandLine;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParameterException;
/** The P2P TLS Config Cli Options. */
public class P2PTLSConfigOptions {
@Option(
names = {"--Xp2p-tls-enabled"},
hidden = true,
description = "Enable P2P TLS functionality (default: ${DEFAULT-VALUE})")
private final Boolean p2pTLSEnabled = false;
@SuppressWarnings({
"FieldCanBeFinal",
"FieldMayBeFinal"
}) // p2pTLSKeyStoreType requires non-final Strings.
@Option(
names = {"--Xp2p-tls-keystore-type"},
hidden = true,
paramLabel = "<NAME>",
description = "P2P service keystore type. Required if P2P TLS is enabled.")
private String p2pTLSKeyStoreType = DEFAULT_KEYSTORE_TYPE;
@Option(
names = {"--Xp2p-tls-keystore-file"},
hidden = true,
paramLabel = MANDATORY_FILE_FORMAT_HELP,
description = "Keystore containing key/certificate for the P2P service.")
private final Path p2pTLSKeyStoreFile = null;
@Option(
names = {"--Xp2p-tls-keystore-password-file"},
hidden = true,
paramLabel = MANDATORY_FILE_FORMAT_HELP,
description =
"File containing password to unlock keystore for the P2P service. Required if P2P TLS is enabled.")
private final Path p2pTLSKeyStorePasswordFile = null;
@SuppressWarnings({
"FieldCanBeFinal",
"FieldMayBeFinal"
}) // p2pTLSTrustStoreType requires non-final Strings.
@Option(
names = {"--Xp2p-tls-truststore-type"},
hidden = true,
paramLabel = "<NAME>",
description = "P2P service truststore type.")
private String p2pTLSTrustStoreType = DEFAULT_KEYSTORE_TYPE;
@Option(
names = {"--Xp2p-tls-truststore-file"},
hidden = true,
paramLabel = MANDATORY_FILE_FORMAT_HELP,
description = "Truststore containing trusted certificates for the P2P service.")
private final Path p2pTLSTrustStoreFile = null;
@Option(
names = {"--Xp2p-tls-truststore-password-file"},
hidden = true,
paramLabel = MANDATORY_FILE_FORMAT_HELP,
description = "File containing password to unlock truststore for the P2P service.")
private final Path p2pTLSTrustStorePasswordFile = null;
@Option(
names = {"--Xp2p-tls-crl-file"},
hidden = true,
paramLabel = MANDATORY_FILE_FORMAT_HELP,
description = "Certificate revocation list for the P2P service.")
private final Path p2pCrlFile = null;
@Option(
names = {"--Xp2p-tls-clienthello-sni"},
hidden = true,
description =
"Whether to send a SNI header in the TLS ClientHello message (default: ${DEFAULT-VALUE})")
private final Boolean p2pTlsClientHelloSniHeaderEnabled = false;
/** Default constructor. */
P2PTLSConfigOptions() {}
/**
* Generate P2p tls configuration.
*
* @param commandLine the command line object to report exceptions
* @return the optional TLSConfiguration
*/
public Optional<TLSConfiguration> p2pTLSConfiguration(final CommandLine commandLine) {
if (!p2pTLSEnabled) {
return Optional.empty();
}
if (p2pTLSKeyStoreType == null) {
throw new ParameterException(
commandLine, "Keystore type is required when p2p TLS is enabled");
}
if (p2pTLSKeyStorePasswordFile == null) {
throw new ParameterException(
commandLine,
"File containing password to unlock keystore is required when p2p TLS is enabled");
}
return Optional.of(
TLSConfiguration.Builder.tlsConfiguration()
.withKeyStoreType(p2pTLSKeyStoreType)
.withKeyStorePath(p2pTLSKeyStoreFile)
.withKeyStorePasswordSupplier(new FileBasedPasswordProvider(p2pTLSKeyStorePasswordFile))
.withKeyStorePasswordPath(p2pTLSKeyStorePasswordFile)
.withTrustStoreType(p2pTLSTrustStoreType)
.withTrustStorePath(p2pTLSTrustStoreFile)
.withTrustStorePasswordSupplier(
null == p2pTLSTrustStorePasswordFile
? null
: new FileBasedPasswordProvider(p2pTLSTrustStorePasswordFile))
.withTrustStorePasswordPath(p2pTLSTrustStorePasswordFile)
.withCrlPath(p2pCrlFile)
.withClientHelloSniEnabled(p2pTlsClientHelloSniHeaderEnabled)
.build());
}
/**
* Check P2P Tls options dependencies.
*
* @param logger the logger
* @param commandLine the command line
*/
public void checkP2PTLSOptionsDependencies(final Logger logger, final CommandLine commandLine) {
CommandLineUtils.checkOptionDependencies(
logger,
commandLine,
"--Xp2p-tls-enabled",
!p2pTLSEnabled,
asList("--Xp2p-tls-keystore-type", "--Xp2p-tls-keystore-password-file"));
}
}

@ -244,17 +244,6 @@ Xpeertask-system-enabled=false
# compatibility flags
compatibility-eth64-forkid-enabled=false
#p2p over ssl
Xp2p-tls-enabled=false
Xp2p-tls-keystore-type="none"
Xp2p-tls-keystore-file="none.file"
Xp2p-tls-truststore-password-file="none"
Xp2p-tls-truststore-type="none"
Xp2p-tls-truststore-file="none.file"
Xp2p-tls-keystore-password-file="none"
Xp2p-tls-crl-file="none.file"
Xp2p-tls-clienthello-sni=false
#contracts
Xevm-jumpdest-cache-weight-kb=32000

@ -35,7 +35,6 @@ dependencies {
implementation project(':datatypes')
implementation project(':ethereum:core')
implementation project(':ethereum:rlp')
implementation project(':pki')
implementation project(':metrics:core')
implementation project(':nat')
implementation project(':util')

@ -44,7 +44,6 @@ import org.hyperledger.besu.ethereum.p2p.rlpx.DisconnectCallback;
import org.hyperledger.besu.ethereum.p2p.rlpx.MessageCallback;
import org.hyperledger.besu.ethereum.p2p.rlpx.RlpxAgent;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.ShouldConnectCallback;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason;
@ -520,7 +519,6 @@ public class DefaultP2PNetwork implements P2PNetwork {
private NatService natService = new NatService(Optional.empty());
private MetricsSystem metricsSystem;
private StorageProvider storageProvider;
private Optional<TLSConfiguration> p2pTLSConfiguration = Optional.empty();
private Blockchain blockchain;
private List<Long> blockNumberForks;
private List<Long> timestampForks;
@ -605,7 +603,6 @@ public class DefaultP2PNetwork implements P2PNetwork {
.peerPrivileges(peerPrivileges)
.localNode(localNode)
.metricsSystem(metricsSystem)
.p2pTLSConfiguration(p2pTLSConfiguration)
.allConnectionsSupplier(allConnectionsSupplier)
.allActiveConnectionsSupplier(allActiveConnectionsSupplier)
.maxPeers(maxPeers)
@ -684,12 +681,6 @@ public class DefaultP2PNetwork implements P2PNetwork {
return this;
}
public Builder p2pTLSConfiguration(final Optional<TLSConfiguration> p2pTLSConfiguration) {
checkNotNull(p2pTLSConfiguration);
this.p2pTLSConfiguration = p2pTLSConfiguration;
return this;
}
public Builder blockchain(final MutableBlockchain blockchain) {
checkNotNull(blockchain);
this.blockchain = blockchain;

@ -30,8 +30,6 @@ import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnectionEvents;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerRlpxPermissions;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.NettyConnectionInitializer;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.NettyTLSConnectionInitializer;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.ShouldConnectCallback;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason;
@ -371,7 +369,6 @@ public class RlpxAgent {
private ConnectionInitializer connectionInitializer;
private PeerConnectionEvents connectionEvents;
private MetricsSystem metricsSystem;
private Optional<TLSConfiguration> p2pTLSConfiguration;
private Supplier<Stream<PeerConnection>> allConnectionsSupplier;
private Supplier<Stream<PeerConnection>> allActiveConnectionsSupplier;
private int maxPeers;
@ -386,23 +383,10 @@ public class RlpxAgent {
connectionEvents = new PeerConnectionEvents(metricsSystem);
}
if (connectionInitializer == null) {
if (p2pTLSConfiguration.isPresent()) {
LOG.debug("TLS Configuration found using NettyTLSConnectionInitializer");
connectionInitializer =
new NettyTLSConnectionInitializer(
nodeKey,
config,
localNode,
connectionEvents,
metricsSystem,
p2pTLSConfiguration.get(),
peerTable);
} else {
LOG.debug("Using default NettyConnectionInitializer");
connectionInitializer =
new NettyConnectionInitializer(
nodeKey, config, localNode, connectionEvents, metricsSystem, peerTable);
}
LOG.debug("Using default NettyConnectionInitializer");
connectionInitializer =
new NettyConnectionInitializer(
nodeKey, config, localNode, connectionEvents, metricsSystem, peerTable);
}
final PeerRlpxPermissions rlpxPermissions =
@ -475,11 +459,6 @@ public class RlpxAgent {
return this;
}
public Builder p2pTLSConfiguration(final Optional<TLSConfiguration> p2pTLSConfiguration) {
this.p2pTLSConfiguration = p2pTLSConfiguration;
return this;
}
public Builder allConnectionsSupplier(
final Supplier<Stream<PeerConnection>> allConnectionsSupplier) {
this.allConnectionsSupplier = allConnectionsSupplier;

@ -1,159 +0,0 @@
/*
* 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.ethereum.p2p.rlpx.connections.netty;
import static org.hyperledger.besu.ethereum.p2p.rlpx.RlpxFrameConstants.LENGTH_FRAME_SIZE;
import static org.hyperledger.besu.ethereum.p2p.rlpx.RlpxFrameConstants.LENGTH_MAX_MESSAGE_FRAME;
import org.hyperledger.besu.cryptoservices.NodeKey;
import org.hyperledger.besu.ethereum.p2p.config.RlpxConfiguration;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.PeerTable;
import org.hyperledger.besu.ethereum.p2p.peers.LocalNode;
import org.hyperledger.besu.ethereum.p2p.peers.Peer;
import org.hyperledger.besu.ethereum.p2p.plain.PlainFramer;
import org.hyperledger.besu.ethereum.p2p.plain.PlainHandshaker;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnectionEventDispatcher;
import org.hyperledger.besu.ethereum.p2p.rlpx.framing.Framer;
import org.hyperledger.besu.ethereum.p2p.rlpx.handshake.HandshakeSecrets;
import org.hyperledger.besu.ethereum.p2p.rlpx.handshake.Handshaker;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.security.GeneralSecurityException;
import java.util.Optional;
import java.util.function.Supplier;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Suppliers;
import io.netty.channel.Channel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.compression.SnappyFrameDecoder;
import io.netty.handler.codec.compression.SnappyFrameEncoder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslHandler;
public class NettyTLSConnectionInitializer extends NettyConnectionInitializer {
private final Optional<Supplier<TLSContextFactory>> tlsContextFactorySupplier;
private final Boolean clientHelloSniHeaderEnabled;
public NettyTLSConnectionInitializer(
final NodeKey nodeKey,
final RlpxConfiguration config,
final LocalNode localNode,
final PeerConnectionEventDispatcher eventDispatcher,
final MetricsSystem metricsSystem,
final TLSConfiguration p2pTLSConfiguration,
final PeerTable peerTable) {
this(
nodeKey,
config,
localNode,
eventDispatcher,
metricsSystem,
defaultTlsContextFactorySupplier(p2pTLSConfiguration),
p2pTLSConfiguration.getClientHelloSniHeaderEnabled(),
peerTable);
}
@VisibleForTesting
NettyTLSConnectionInitializer(
final NodeKey nodeKey,
final RlpxConfiguration config,
final LocalNode localNode,
final PeerConnectionEventDispatcher eventDispatcher,
final MetricsSystem metricsSystem,
final Supplier<TLSContextFactory> tlsContextFactorySupplier,
final Boolean clientHelloSniHeaderEnabled,
final PeerTable peerTable) {
super(nodeKey, config, localNode, eventDispatcher, metricsSystem, peerTable);
if (tlsContextFactorySupplier != null) {
this.tlsContextFactorySupplier =
Optional.of(Suppliers.memoize(tlsContextFactorySupplier::get));
} else {
this.tlsContextFactorySupplier = Optional.empty();
}
this.clientHelloSniHeaderEnabled = clientHelloSniHeaderEnabled;
}
@Override
void addAdditionalOutboundHandlers(final Channel ch, final Peer peer)
throws GeneralSecurityException {
if (tlsContextFactorySupplier.isPresent()) {
final SslContext clientSslContext =
tlsContextFactorySupplier.get().get().createNettyClientSslContext();
final EnodeURL enode = peer.getEnodeURL();
final SslHandler sslHandler = createClientSslHandler(ch, clientSslContext, enode);
addHandlersToChannelPipeline(ch, sslHandler);
}
}
private SslHandler createClientSslHandler(
final Channel ch, final SslContext sslContext, final EnodeURL enode) {
if (this.clientHelloSniHeaderEnabled) {
return sslContext.newHandler(
ch.alloc(), enode.getHost(), enode.getListeningPort().orElseThrow());
} else {
return sslContext.newHandler(ch.alloc());
}
}
@Override
void addAdditionalInboundHandlers(final Channel ch) throws GeneralSecurityException {
if (tlsContextFactorySupplier.isPresent()) {
final SslContext serverSslContext =
tlsContextFactorySupplier.get().get().createNettyServerSslContext();
addHandlersToChannelPipeline(ch, serverSslContext.newHandler(ch.alloc()));
}
}
private void addHandlersToChannelPipeline(final Channel ch, final SslHandler sslHandler) {
ch.pipeline().addLast(sslHandler);
ch.pipeline().addLast(new SnappyFrameDecoder());
ch.pipeline().addLast(new SnappyFrameEncoder());
ch.pipeline()
.addLast(
new LengthFieldBasedFrameDecoder(
LENGTH_MAX_MESSAGE_FRAME, 0, LENGTH_FRAME_SIZE, 0, LENGTH_FRAME_SIZE));
ch.pipeline().addLast(new LengthFieldPrepender(LENGTH_FRAME_SIZE));
}
@Override
public Handshaker buildInstance() {
return new PlainHandshaker();
}
@Override
public Framer buildFramer(final HandshakeSecrets secrets) {
return new PlainFramer();
}
@VisibleForTesting
static Supplier<TLSContextFactory> defaultTlsContextFactorySupplier(
final TLSConfiguration tlsConfiguration) {
if (tlsConfiguration == null) {
throw new IllegalStateException("TLSConfiguration cannot be null when using TLS");
}
return () -> {
try {
return TLSContextFactory.buildFrom(tlsConfiguration);
} catch (final Exception e) {
throw new IllegalStateException("Error creating TLSContextFactory", e);
}
};
}
}

@ -1,197 +0,0 @@
/*
* 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.ethereum.p2p.rlpx.connections.netty;
import static java.util.Objects.requireNonNull;
import java.nio.file.Path;
import java.util.function.Supplier;
public class TLSConfiguration {
private final String keyStoreType;
private final Path keyStorePath;
private final Supplier<String> keyStorePasswordSupplier;
private final Path keyStorePasswordPath;
private final String trustStoreType;
private final Path trustStorePath;
private final Supplier<String> trustStorePasswordSupplier;
private final Path trustStorePasswordPath;
private final Path crlPath;
private final String[] allowedProtocols;
private final Boolean clientHelloSniHeaderEnabled;
private TLSConfiguration(
final String keyStoreType,
final Path keyStorePath,
final Supplier<String> keyStorePasswordSupplier,
final Path keyStorePasswordPath,
final String trustStoreType,
final Path trustStorePath,
final Supplier<String> trustStorePasswordSupplier,
final Path trustStorePasswordPath,
final Path crlPath,
final String[] allowedProtocols,
final Boolean clientHelloSniHeaderEnabled) {
this.keyStoreType = keyStoreType;
this.keyStorePath = keyStorePath;
this.keyStorePasswordSupplier = keyStorePasswordSupplier;
this.keyStorePasswordPath = keyStorePasswordPath;
this.trustStoreType = trustStoreType;
this.trustStorePath = trustStorePath;
this.trustStorePasswordSupplier = trustStorePasswordSupplier;
this.trustStorePasswordPath = trustStorePasswordPath;
this.crlPath = crlPath;
this.allowedProtocols = allowedProtocols;
this.clientHelloSniHeaderEnabled = clientHelloSniHeaderEnabled;
}
public String getKeyStoreType() {
return keyStoreType;
}
public Path getKeyStorePath() {
return keyStorePath;
}
public String getKeyStorePassword() {
return null == keyStorePasswordSupplier ? null : keyStorePasswordSupplier.get();
}
public Path getKeyStorePasswordPath() {
return keyStorePasswordPath;
}
public String getTrustStoreType() {
return trustStoreType;
}
public Path getTrustStorePath() {
return trustStorePath;
}
public String getTrustStorePassword() {
return null == trustStorePasswordSupplier ? null : trustStorePasswordSupplier.get();
}
public Path getTrustStorePasswordPath() {
return trustStorePasswordPath;
}
public Path getCrlPath() {
return crlPath;
}
public String[] getAllowedProtocols() {
return allowedProtocols;
}
public Boolean getClientHelloSniHeaderEnabled() {
return clientHelloSniHeaderEnabled;
}
public static final class Builder {
private String keyStoreType;
private Path keyStorePath;
private Supplier<String> keyStorePasswordSupplier;
private Path keyStorePasswordPath;
private String trustStoreType;
private Path trustStorePath;
private Supplier<String> trustStorePasswordSupplier;
private Path trustStorePasswordPath;
private Path crlPath;
private String[] allowedProtocols;
private Boolean clientHelloSniHeaderEnabled;
private Builder() {}
public static Builder tlsConfiguration() {
return new Builder();
}
public Builder withKeyStoreType(final String keyStoreType) {
this.keyStoreType = keyStoreType;
return this;
}
public Builder withKeyStorePath(final Path keyStorePath) {
this.keyStorePath = keyStorePath;
return this;
}
public Builder withKeyStorePasswordPath(final Path keyStorePasswordPath) {
this.keyStorePasswordPath = keyStorePasswordPath;
return this;
}
public Builder withKeyStorePasswordSupplier(final Supplier<String> keyStorePasswordSupplier) {
this.keyStorePasswordSupplier = keyStorePasswordSupplier;
return this;
}
public Builder withTrustStoreType(final String trustStoreType) {
this.trustStoreType = trustStoreType;
return this;
}
public Builder withTrustStorePath(final Path trustStorePath) {
this.trustStorePath = trustStorePath;
return this;
}
public Builder withTrustStorePasswordSupplier(
final Supplier<String> trustStorePasswordSupplier) {
this.trustStorePasswordSupplier = trustStorePasswordSupplier;
return this;
}
public Builder withTrustStorePasswordPath(final Path trustStorePasswordPath) {
this.trustStorePasswordPath = trustStorePasswordPath;
return this;
}
public Builder withCrlPath(final Path crlPath) {
this.crlPath = crlPath;
return this;
}
public Builder withAllowedProtocols(final String[] allowedProtocols) {
this.allowedProtocols = allowedProtocols;
return this;
}
public Builder withClientHelloSniEnabled(final Boolean clientHelloSniHeaderEnabled) {
this.clientHelloSniHeaderEnabled = clientHelloSniHeaderEnabled;
return this;
}
public TLSConfiguration build() {
requireNonNull(keyStoreType, "Key Store Type must not be null");
requireNonNull(keyStorePasswordSupplier, "Key Store password supplier must not be null");
return new TLSConfiguration(
keyStoreType,
keyStorePath,
keyStorePasswordSupplier,
keyStorePasswordPath,
trustStoreType,
trustStorePath,
trustStorePasswordSupplier,
trustStorePasswordPath,
crlPath,
allowedProtocols,
clientHelloSniHeaderEnabled);
}
}
}

@ -1,230 +0,0 @@
/*
* 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.ethereum.p2p.rlpx.connections.netty;
import org.hyperledger.besu.pki.keystore.HardwareKeyStoreWrapper;
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper;
import org.hyperledger.besu.pki.keystore.SoftwareKeyStoreWrapper;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import io.netty.handler.ssl.ClientAuth;
import io.netty.handler.ssl.IdentityCipherSuiteFilter;
import io.netty.handler.ssl.JdkSslContext;
import io.netty.handler.ssl.SslContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TLSContextFactory {
private static final Logger LOG = LoggerFactory.getLogger(TLSContextFactory.class);
private static final String[] ALLOWED_PROTOCOLS = {"TLSv1.3"};
private static final String KEYMANAGER_FACTORY_ALGORITHM = "PKIX";
private static final String TRUSTMANAGER_FACTORY_ALGORITHM = "PKIX";
private List<String> enabledCipherSuites = null;
private KeyManagerFactory kmf;
private TrustManagerFactory tmf;
private Collection<X509CRL> crls;
private String[] allowedProtocols;
protected TLSContextFactory() {}
protected TLSContextFactory(
final String keystorePass,
final KeyStoreWrapper keystoreWrapper,
final List<String> configuredCipherSuites,
final String[] allowedProtocols)
throws GeneralSecurityException, IOException {
kmf = getKeyManagerFactory(keystoreWrapper.getKeyStore(), keystorePass);
tmf = getTrustManagerFactory(keystoreWrapper.getTrustStore());
crls = keystoreWrapper.getCRLs();
if (configuredCipherSuites != null && !configuredCipherSuites.isEmpty()) {
enabledCipherSuites = configuredCipherSuites;
}
this.allowedProtocols = null == allowedProtocols ? ALLOWED_PROTOCOLS : allowedProtocols;
}
public static TLSContextFactory getInstance(
final String keyStorePassword, final KeyStoreWrapper wrapper, final String[] allowedProtocols)
throws GeneralSecurityException, IOException {
return new TLSContextFactory(keyStorePassword, wrapper, null, allowedProtocols);
}
public static TLSContextFactory getInstance(
final String keyStorePassword, final KeyStoreWrapper wrapper)
throws GeneralSecurityException, IOException {
return new TLSContextFactory(keyStorePassword, wrapper, null, null);
}
public SslContext createNettyServerSslContext()
throws NoSuchAlgorithmException, KeyManagementException {
final List<String> enabledCipherSuites = getEnabledCipherSuites();
return new JdkSslContext(
createJavaSslContext(),
false,
enabledCipherSuites,
IdentityCipherSuiteFilter.INSTANCE,
null,
ClientAuth.REQUIRE,
null,
false);
}
public SslContext createNettyClientSslContext()
throws NoSuchAlgorithmException, KeyManagementException {
final List<String> enabledCipherSuites = getEnabledCipherSuites();
return new JdkSslContext(
createJavaSslContext(),
true,
enabledCipherSuites,
IdentityCipherSuiteFilter.INSTANCE,
null,
ClientAuth.NONE,
null,
false);
}
public SSLContext createJavaSslContext() throws NoSuchAlgorithmException, KeyManagementException {
final SSLContext context = SSLContext.getInstance(getTlsProtocol());
context.init(
kmf.getKeyManagers(),
null == crls || crls.isEmpty() ? tmf.getTrustManagers() : wrap(tmf.getTrustManagers()),
null);
return context;
}
protected TrustManager[] wrap(final TrustManager[] trustMgrs) {
final TrustManager[] ret = trustMgrs.clone();
for (int i = 0; i < ret.length; i++) {
TrustManager trustMgr = ret[i];
if (trustMgr instanceof X509TrustManager) {
X509TrustManager x509TrustManager = (X509TrustManager) trustMgr;
ret[i] =
new X509TrustManager() {
@Override
public void checkClientTrusted(
final X509Certificate[] x509Certificates, final String s)
throws CertificateException {
checkRevoked(x509Certificates);
x509TrustManager.checkClientTrusted(x509Certificates, s);
}
@Override
public void checkServerTrusted(
final X509Certificate[] x509Certificates, final String s)
throws CertificateException {
checkRevoked(x509Certificates);
x509TrustManager.checkServerTrusted(x509Certificates, s);
}
private void checkRevoked(final X509Certificate[] x509Certificates)
throws CertificateException {
for (X509CRL crl : crls) {
for (X509Certificate cert : x509Certificates) {
if (crl.isRevoked(cert)) {
throw new CertificateException("Certificate revoked");
}
}
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return x509TrustManager.getAcceptedIssuers();
}
};
}
}
return ret;
}
protected TrustManagerFactory getTrustManagerFactory(final KeyStore truststore)
throws GeneralSecurityException {
final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TRUSTMANAGER_FACTORY_ALGORITHM);
tmf.init(truststore);
return tmf;
}
protected KeyManagerFactory getKeyManagerFactory(
final KeyStore keystore, final String keystorePassword) throws GeneralSecurityException {
final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEYMANAGER_FACTORY_ALGORITHM);
kmf.init(keystore, keystorePassword.toCharArray());
return kmf;
}
private List<String> getEnabledCipherSuites() {
final String protocol = getTlsProtocol();
try {
if (enabledCipherSuites == null || enabledCipherSuites.isEmpty()) {
final SSLContext sslcontext = SSLContext.getInstance(protocol);
sslcontext.init(null, null, null);
enabledCipherSuites = Arrays.asList(sslcontext.createSSLEngine().getEnabledCipherSuites());
}
} catch (final NoSuchAlgorithmException | KeyManagementException e) {
LOG.warn(
"Could not get list of enabled (JDK) cipher suites for protocol:{}, reverting to Netty's default ones.",
protocol);
}
return enabledCipherSuites;
}
private String getTlsProtocol() {
return Arrays.stream(allowedProtocols).max(Comparator.naturalOrder()).orElse(null);
}
public static TLSContextFactory buildFrom(final TLSConfiguration config)
throws GeneralSecurityException, IOException {
TLSContextFactory ret = null;
if (null != config) {
LOG.info("Initializing SSL Context using {} keystore.", config.getKeyStoreType());
KeyStoreWrapper wrapper =
KeyStoreWrapper.KEYSTORE_TYPE_PKCS11.equalsIgnoreCase(config.getKeyStoreType())
? new HardwareKeyStoreWrapper(
config.getKeyStorePassword(), config.getKeyStorePath(), config.getCrlPath())
: new SoftwareKeyStoreWrapper(
config.getKeyStoreType(),
config.getKeyStorePath(),
config.getKeyStorePassword(),
config.getTrustStoreType(),
config.getTrustStorePath(),
config.getTrustStorePassword(),
config.getCrlPath());
ret =
TLSContextFactory.getInstance(
config.getKeyStorePassword(), wrapper, config.getAllowedProtocols());
}
return ret;
}
}

@ -97,7 +97,7 @@ public final class DefaultP2PNetworkTest {
lenient().when(discoveryAgent.checkForkId(any())).thenReturn(true);
lenient()
.when(discoveryAgent.start(anyInt()))
.thenReturn(CompletableFuture.completedFuture(Integer.valueOf(30301)));
.thenReturn(CompletableFuture.completedFuture(30301));
}
@Test

@ -16,8 +16,6 @@ package org.hyperledger.besu.ethereum.p2p.network;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Fail.fail;
import static org.hyperledger.besu.pki.keystore.KeyStoreWrapper.KEYSTORE_TYPE_PKCS12;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@ -39,10 +37,7 @@ import org.hyperledger.besu.ethereum.p2p.peers.Peer;
import org.hyperledger.besu.ethereum.p2p.permissions.PeerPermissions;
import org.hyperledger.besu.ethereum.p2p.permissions.PeerPermissionsDenylist;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.AbstractMessageData;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Message;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MockSubProtocol;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.ShouldConnectCallback;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.SubProtocol;
@ -51,12 +46,8 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.data.EnodeURL;
import java.net.InetAddress;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
@ -89,8 +80,8 @@ public class P2PPlainNetworkTest {
@Test
public void handshaking() throws Exception {
final NodeKey nodeKey = NodeKeyUtils.generate();
try (final P2PNetwork listener = builder("partner1client1").nodeKey(nodeKey).build();
final P2PNetwork connector = builder("partner2client1").build()) {
try (final P2PNetwork listener = builder().nodeKey(nodeKey).build();
final P2PNetwork connector = builder().build()) {
listener.getRlpxAgent().subscribeConnectRequest(testCallback);
connector.getRlpxAgent().subscribeConnectRequest(testCallback);
@ -113,8 +104,8 @@ public class P2PPlainNetworkTest {
@Test
public void preventMultipleConnections() throws Exception {
final NodeKey listenNodeKey = NodeKeyUtils.generate();
try (final P2PNetwork listener = builder("partner1client1").nodeKey(listenNodeKey).build();
final P2PNetwork connector = builder("partner2client1").build()) {
try (final P2PNetwork listener = builder().nodeKey(listenNodeKey).build();
final P2PNetwork connector = builder().build()) {
listener.getRlpxAgent().subscribeConnectRequest(testCallback);
connector.getRlpxAgent().subscribeConnectRequest(testCallback);
@ -155,10 +146,9 @@ public class P2PPlainNetworkTest {
RlpxConfiguration.create()
.setBindPort(0)
.setSupportedProtocols(MockSubProtocol.create()));
try (final P2PNetwork listener =
builder("partner1client1").nodeKey(nodeKey).config(listenerConfig).build();
final P2PNetwork connector1 = builder("partner1client1").build();
final P2PNetwork connector2 = builder("partner2client1").build()) {
try (final P2PNetwork listener = builder().nodeKey(nodeKey).config(listenerConfig).build();
final P2PNetwork connector1 = builder().build();
final P2PNetwork connector2 = builder().build()) {
listener.getRlpxAgent().subscribeConnectRequest(testCallback);
connector1.getRlpxAgent().subscribeConnectRequest(testCallback);
connector2.getRlpxAgent().subscribeConnectRequest((p, d) -> false);
@ -202,15 +192,9 @@ public class P2PPlainNetworkTest {
final SubProtocol subprotocol2 = MockSubProtocol.create("oth");
final Capability cap2 = Capability.create(subprotocol2.getName(), 63);
try (final P2PNetwork listener =
builder("partner1client1")
.nodeKey(listenerNodeKey)
.supportedCapabilities(cap1)
.build();
builder().nodeKey(listenerNodeKey).supportedCapabilities(cap1).build();
final P2PNetwork connector =
builder("partner2client1")
.nodeKey(connectorNodeKey)
.supportedCapabilities(cap2)
.build()) {
builder().nodeKey(connectorNodeKey).supportedCapabilities(cap2).build()) {
listener.getRlpxAgent().subscribeConnectRequest(testCallback);
connector.getRlpxAgent().subscribeConnectRequest(testCallback);
@ -230,9 +214,8 @@ public class P2PPlainNetworkTest {
public void rejectIncomingConnectionFromDenylistedPeer() throws Exception {
final PeerPermissionsDenylist localDenylist = PeerPermissionsDenylist.create();
try (final P2PNetwork localNetwork =
builder("partner1client1").peerPermissions(localDenylist).build();
final P2PNetwork remoteNetwork = builder("partner2client1").build()) {
try (final P2PNetwork localNetwork = builder().peerPermissions(localDenylist).build();
final P2PNetwork remoteNetwork = builder().build()) {
localNetwork.getRlpxAgent().subscribeConnectRequest(testCallback);
remoteNetwork.getRlpxAgent().subscribeConnectRequest(testCallback);
@ -280,9 +263,8 @@ public class P2PPlainNetworkTest {
final PeerPermissions peerPermissions = mock(PeerPermissions.class);
when(peerPermissions.isPermitted(any(), any(), any())).thenReturn(true);
try (final P2PNetwork localNetwork =
builder("partner1client1").peerPermissions(peerPermissions).build();
final P2PNetwork remoteNetwork = builder("partner2client1").build()) {
try (final P2PNetwork localNetwork = builder().peerPermissions(peerPermissions).build();
final P2PNetwork remoteNetwork = builder().build()) {
localNetwork.getRlpxAgent().subscribeConnectRequest(testCallback);
remoteNetwork.getRlpxAgent().subscribeConnectRequest(testCallback);
@ -323,89 +305,8 @@ public class P2PPlainNetworkTest {
}
}
@Test
public void p2pOverTlsCanHandleRecordFragmentation() throws Exception {
// Given
final int tlsRecordSize = 16 * 1024;
final int threeTlsRecords = 2 * tlsRecordSize + 1;
final LargeMessageData largeMessageData =
new LargeMessageData(Bytes.of(buildPaddedMessage(threeTlsRecords)));
final NodeKey nodeKey = NodeKeyUtils.generate();
try (final P2PNetwork listener = builder("partner1client1").nodeKey(nodeKey).build();
final P2PNetwork connector = builder("partner2client1").build()) {
listener.getRlpxAgent().subscribeConnectRequest(testCallback);
connector.getRlpxAgent().subscribeConnectRequest(testCallback);
final CompletableFuture<DisconnectReason> disconnectReasonFuture = new CompletableFuture<>();
listener.subscribeDisconnect(
(peerConnection, reason, initiatedByPeer) -> {
if (!DisconnectReason.CLIENT_QUITTING.equals(
reason)) { // client quitting is the valid end state
disconnectReasonFuture.complete(reason);
}
});
final CompletableFuture<Message> successfulMessageFuture = new CompletableFuture<>();
listener.subscribe(
Capability.create("eth", 63),
(capability, message) -> {
if (message.getData().getCode() == LargeMessageData.VALID_ETH_MESSAGE_CODE) {
successfulMessageFuture.complete(message);
}
});
listener.start();
connector.start();
final EnodeURL listenerEnode = listener.getLocalEnode().get();
final Bytes listenId = listenerEnode.getNodeId();
final int listenPort = listenerEnode.getListeningPort().get();
final PeerConnection peerConnection =
connector.connect(createPeer(listenId, listenPort)).get(30000L, TimeUnit.SECONDS);
// When
peerConnection.sendForProtocol("eth", largeMessageData);
// Then
CompletableFuture.anyOf(disconnectReasonFuture, successfulMessageFuture)
.thenAccept(
successOrFailure -> {
if (successOrFailure instanceof DisconnectReason) {
fail(
"listener disconnected due to "
+ ((DisconnectReason) successOrFailure).name());
} else {
final Message receivedMessage = (Message) successOrFailure;
assertThat(receivedMessage.getData().getData())
.isEqualTo(largeMessageData.getData());
}
})
.get(30L, TimeUnit.SECONDS);
}
}
private final ShouldConnectCallback testCallback = (p, d) -> true;
private static class LargeMessageData extends AbstractMessageData {
public static final int VALID_ETH_MESSAGE_CODE = 0x07;
private LargeMessageData(final Bytes data) {
super(data);
}
@Override
public int getCode() {
return VALID_ETH_MESSAGE_CODE;
}
}
private byte[] buildPaddedMessage(final int messageSize) {
final byte[] bytes = new byte[messageSize];
Arrays.fill(bytes, (byte) 9);
return bytes;
}
private Peer createPeer(final Bytes nodeId, final int listenPort) {
return DefaultPeer.fromEnodeURL(
EnodeURLImpl.builder()
@ -415,35 +316,7 @@ public class P2PPlainNetworkTest {
.build());
}
private static Path toPath(final String path) {
try {
return Path.of(Objects.requireNonNull(P2PPlainNetworkTest.class.getResource(path)).toURI());
} catch (final URISyntaxException e) {
throw new RuntimeException("Error converting to URI.", e);
}
}
public Optional<TLSConfiguration> p2pTLSEnabled(final String clientDirName) {
final String parentPath = "/keys";
final String keystorePath = parentPath + "/%s/client1.p12";
final String truststorePath = parentPath + "/%s/truststore.p12";
final String crl = parentPath + "/crl/crl.pem";
final TLSConfiguration.Builder builder = TLSConfiguration.Builder.tlsConfiguration();
builder
.withKeyStoreType(KEYSTORE_TYPE_PKCS12)
.withKeyStorePath(toPath(String.format(keystorePath, clientDirName)))
.withKeyStorePasswordSupplier(() -> "test123")
// .withKeyStorePasswordPath(toPath(String.format(nsspin, name)))
.withTrustStoreType(KEYSTORE_TYPE_PKCS12)
.withTrustStorePath(toPath(String.format(truststorePath, clientDirName)))
.withTrustStorePasswordSupplier(() -> "test123")
.withCrlPath(toPath(crl))
.withClientHelloSniEnabled(false);
return Optional.of(builder.build());
}
private DefaultP2PNetwork.Builder builder(final String clientDirName) {
private DefaultP2PNetwork.Builder builder() {
final MutableBlockchain blockchainMock = mock(MutableBlockchain.class);
final Block blockMock = mock(Block.class);
when(blockMock.getHash()).thenReturn(Hash.ZERO);
@ -452,7 +325,6 @@ public class P2PPlainNetworkTest {
.vertx(vertx)
.config(config)
.nodeKey(NodeKeyUtils.generate())
.p2pTLSConfiguration(p2pTLSEnabled(clientDirName))
.metricsSystem(new NoOpMetricsSystem())
.supportedCapabilities(Arrays.asList(Capability.create("eth", 63)))
.storageProvider(new InMemoryKeyValueStorageProvider())

@ -1,195 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.ethereum.p2p.rlpx.connections.netty;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.cryptoservices.NodeKey;
import org.hyperledger.besu.ethereum.p2p.config.RlpxConfiguration;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.PeerTable;
import org.hyperledger.besu.ethereum.p2p.peers.LocalNode;
import org.hyperledger.besu.ethereum.p2p.peers.Peer;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnectionEventDispatcher;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.data.EnodeURL;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import com.google.common.collect.ImmutableList;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.compression.SnappyFrameDecoder;
import io.netty.handler.codec.compression.SnappyFrameEncoder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslHandler;
import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class NettyTLSConnectionInitializerTest {
private static final String PEER_HOST = "hyperledger.org";
private static final int PEER_PORT = 30303;
@Mock private NodeKey nodeKey;
@Mock private RlpxConfiguration rlpxConfiguration;
@Mock private LocalNode localNode;
@Mock private PeerConnectionEventDispatcher eventDispatcher;
@Mock private TLSContextFactory tlsContextFactory;
@Mock private SslContext clientSslContext;
@Mock private SslContext serverSslContext;
@Mock private SslHandler clientSslHandler;
@Mock private SslHandler serverSslHandler;
@Mock private Peer peer;
@Mock private EnodeURL enodeURL;
private NettyTLSConnectionInitializer nettyTLSConnectionInitializer;
@BeforeEach
public void before() throws Exception {
nettyTLSConnectionInitializer = createNettyTLSConnectionInitializer(false);
when(tlsContextFactory.createNettyServerSslContext()).thenReturn(serverSslContext);
when(serverSslContext.newHandler(any())).thenReturn(serverSslHandler);
when(tlsContextFactory.createNettyClientSslContext()).thenReturn(clientSslContext);
when(clientSslContext.newHandler(any())).thenReturn(clientSslHandler);
when(peer.getEnodeURL()).thenReturn(enodeURL);
when(enodeURL.getHost()).thenReturn(PEER_HOST);
when(enodeURL.getListeningPort()).thenReturn(Optional.of(PEER_PORT));
}
private NettyTLSConnectionInitializer createNettyTLSConnectionInitializer(
final boolean clientHelloSniHeaderEnabled) {
return new NettyTLSConnectionInitializer(
nodeKey,
rlpxConfiguration,
localNode,
eventDispatcher,
new NoOpMetricsSystem(),
() -> tlsContextFactory,
clientHelloSniHeaderEnabled,
new PeerTable(Bytes.random(64)));
}
@Test
public void addAdditionalOutboundHandlersIncludesAllExpectedHandlersToChannelPipeline()
throws Exception {
final EmbeddedChannel embeddedChannel = new EmbeddedChannel();
nettyTLSConnectionInitializer.addAdditionalOutboundHandlers(embeddedChannel, peer);
// TLS
assertThat(embeddedChannel.pipeline().get(SslHandler.class)).isEqualTo(clientSslHandler);
// Snappy compression
assertThat(embeddedChannel.pipeline().get(SnappyFrameDecoder.class)).isNotNull();
assertThat(embeddedChannel.pipeline().get(SnappyFrameEncoder.class)).isNotNull();
// Message Framing
assertThat(embeddedChannel.pipeline().get(LengthFieldBasedFrameDecoder.class)).isNotNull();
assertThat(embeddedChannel.pipeline().get(LengthFieldPrepender.class)).isNotNull();
assertHandlersOrderInPipeline(embeddedChannel.pipeline());
}
@Test
public void addAdditionalOutboundHandlersUsesSslHandlerWithSniHeaderEnabledIfConfigured()
throws Exception {
nettyTLSConnectionInitializer = createNettyTLSConnectionInitializer(true);
when(clientSslContext.newHandler(any(), eq(PEER_HOST), eq(PEER_PORT)))
.thenReturn(clientSslHandler);
final EmbeddedChannel embeddedChannel = new EmbeddedChannel();
nettyTLSConnectionInitializer.addAdditionalOutboundHandlers(embeddedChannel, peer);
// Handler with SNI params was created
verify(clientSslContext).newHandler(any(), eq(PEER_HOST), eq(PEER_PORT));
// Other handlers are still present as expected
assertHandlersOrderInPipeline(embeddedChannel.pipeline());
}
@Test
public void addAdditionalInboundHandlersIncludesAllExpectedHandlersToChannelPipeline()
throws Exception {
final EmbeddedChannel embeddedChannel = new EmbeddedChannel();
nettyTLSConnectionInitializer.addAdditionalInboundHandlers(embeddedChannel);
// TLS
assertThat(embeddedChannel.pipeline().get(SslHandler.class)).isEqualTo(serverSslHandler);
// Snappy compression
assertThat(embeddedChannel.pipeline().get(SnappyFrameDecoder.class)).isNotNull();
assertThat(embeddedChannel.pipeline().get(SnappyFrameEncoder.class)).isNotNull();
// Message Framing
assertThat(embeddedChannel.pipeline().get(LengthFieldBasedFrameDecoder.class)).isNotNull();
assertThat(embeddedChannel.pipeline().get(LengthFieldPrepender.class)).isNotNull();
assertHandlersOrderInPipeline(embeddedChannel.pipeline());
}
private void assertHandlersOrderInPipeline(final ChannelPipeline pipeline) {
// Appending '#0' because Netty adds it to the handler's names
final ArrayList<String> expectedHandlerNamesInOrder =
new ArrayList<>(
ImmutableList.of(
"SslHandler#0",
"SnappyFrameDecoder#0",
"SnappyFrameEncoder#0",
"LengthFieldBasedFrameDecoder#0",
"LengthFieldPrepender#0",
"DefaultChannelPipeline$TailContext#0")); // This final handler is Netty's default
final List<String> actualHandlerNamesInOrder = pipeline.names();
assertThat(actualHandlerNamesInOrder).isEqualTo(expectedHandlerNamesInOrder);
}
@Test
public void defaultTlsContextFactorySupplierThrowsErrorWithNullTLSConfiguration() {
assertThatThrownBy(() -> NettyTLSConnectionInitializer.defaultTlsContextFactorySupplier(null))
.isInstanceOf(IllegalStateException.class)
.hasMessage("TLSConfiguration cannot be null when using TLS");
}
@Test
public void defaultTlsContextFactorySupplierCapturesInternalError() {
final TLSConfiguration tlsConfiguration = mock(TLSConfiguration.class);
when(tlsConfiguration.getKeyStoreType()).thenThrow(new RuntimeException());
assertThatThrownBy(
() ->
NettyTLSConnectionInitializer.defaultTlsContextFactorySupplier(tlsConfiguration)
.get())
.isInstanceOf(IllegalStateException.class)
.hasMessage("Error creating TLSContextFactory");
}
}

@ -1,504 +0,0 @@
/*
* 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.ethereum.p2p.rlpx.connections.netty;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.pki.keystore.KeyStoreWrapper.KEYSTORE_TYPE_PKCS12;
import org.hyperledger.besu.pki.PkiException;
import org.hyperledger.besu.pki.keystore.HardwareKeyStoreWrapper;
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper;
import org.hyperledger.besu.pki.keystore.SoftwareKeyStoreWrapper;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslHandler;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.OS;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class TLSContextFactoryTest {
// see resources/keys/README.md for setup details.
private static final String keystorePassword = "test123";
private static final Logger LOG = LoggerFactory.getLogger(TLSContextFactoryTest.class);
private static final int MAX_NUMBER_MESSAGES = 10;
private static final String CRL_PEM = "/keys/crl/crl.pem";
private static final String PARTNER1_CLIENT1_PKCS11 = "/keys/partner1client1/nss.cfg";
private static final String PARTNER1_CLIENT1_KEYSTORE = "/keys/partner1client1/client1.p12";
private static final String PARTNET1_CLIENT2_KEYSTORE = "/keys/partner1client2rvk/client2.p12";
private static final String PARTNER2_CLIENT1_KEYSTORE = "/keys/partner2client1/client1.p12";
private static final String PARTNER2_CLIENT2_KEYSTORE = "/keys/partner2client2rvk/client2.p12";
private static final String INVALIDPARTNER1_CLIENT1_KEYSTORE =
"/keys/invalidpartner1client1/client1.p12";
private static final String PARTNER1_CLIENT1_TRUSTSTORE = "/keys/partner1client1/truststore.p12";
private static final String PARTNET1_CLIENT2_TRUSTSTORE =
"/keys/partner1client2rvk/truststore.p12";
private static final String PARTNER2_CLIENT1_TRUSTSTORE = "/keys/partner2client1/truststore.p12";
private static final String PARTNER2_CLIENT2_TRUSTSTORE =
"/keys/partner2client2rvk/truststore.p12";
private static final String INVALIDPARTNER1_CLIENT1_TRUSTSTORE =
"/keys/invalidpartner1client1/truststore.p12";
private Server server;
private Client client;
static Collection<Object[]> hardwareKeysData() {
return Arrays.asList(
new Object[][] {
{
"PKCS11 server Partner1 Client1 -> PKCS12 client Partner2 Client1 SuccessfulConnection",
true,
getHardwareKeyStoreWrapper(PARTNER1_CLIENT1_PKCS11, CRL_PEM),
getSoftwareKeyStoreWrapper(
PARTNER2_CLIENT1_KEYSTORE, PARTNER2_CLIENT1_TRUSTSTORE, CRL_PEM),
Optional.empty(),
Optional.empty()
},
{
"PKCS11 server Partner1 Client1 -> PKCS12 client InvalidPartner1 Client1 FailedConnection",
false,
getHardwareKeyStoreWrapper(PARTNER1_CLIENT1_PKCS11, CRL_PEM),
getSoftwareKeyStoreWrapper(
INVALIDPARTNER1_CLIENT1_KEYSTORE, INVALIDPARTNER1_CLIENT1_TRUSTSTORE, null),
Optional.empty(),
Optional.of("certificate_unknown")
},
{
"PKCS11 server Partner1 Client1 -> PKCS12 client Partner2 Client2 revoked FailedConnection",
false,
getHardwareKeyStoreWrapper(PARTNER1_CLIENT1_PKCS11, CRL_PEM),
getSoftwareKeyStoreWrapper(
PARTNER2_CLIENT2_KEYSTORE, PARTNER2_CLIENT2_TRUSTSTORE, null),
Optional.of("Certificate revoked"),
Optional.of("certificate_unknown")
},
});
}
static Collection<Object[]> softwareKeysData() {
return Arrays.asList(
new Object[][] {
{
"PKCS12 server Partner1 Client1 -> PKCS12 client Partner2 Client1 SuccessfulConnection",
true,
getSoftwareKeyStoreWrapper(
PARTNER1_CLIENT1_KEYSTORE, PARTNER1_CLIENT1_TRUSTSTORE, CRL_PEM),
getSoftwareKeyStoreWrapper(
PARTNER2_CLIENT1_KEYSTORE, PARTNER2_CLIENT1_TRUSTSTORE, CRL_PEM),
Optional.empty(),
Optional.empty()
},
{
"PKCS12 server Partner2 Client1 -> PKCS12 client Partner1 Client1 SuccessfulConnection",
true,
getSoftwareKeyStoreWrapper(
PARTNER2_CLIENT1_KEYSTORE, PARTNER2_CLIENT1_TRUSTSTORE, CRL_PEM),
getSoftwareKeyStoreWrapper(
PARTNER1_CLIENT1_KEYSTORE, PARTNER1_CLIENT1_TRUSTSTORE, CRL_PEM),
Optional.empty(),
Optional.empty()
},
{
"PKCS12 server Partner1 Client1 -> PKCS12 client InvalidPartner1 Client1 FailedConnection",
false,
getSoftwareKeyStoreWrapper(
PARTNER1_CLIENT1_KEYSTORE, PARTNER1_CLIENT1_TRUSTSTORE, CRL_PEM),
getSoftwareKeyStoreWrapper(
INVALIDPARTNER1_CLIENT1_KEYSTORE, INVALIDPARTNER1_CLIENT1_TRUSTSTORE, null),
Optional.empty(),
Optional.of("certificate_unknown")
},
{
"PKCS12 server InvalidPartner1 Client1 -> PKCS12 client Partner1 Client1 FailedConnection",
false,
getSoftwareKeyStoreWrapper(
INVALIDPARTNER1_CLIENT1_KEYSTORE, INVALIDPARTNER1_CLIENT1_TRUSTSTORE, null),
getSoftwareKeyStoreWrapper(
PARTNER1_CLIENT1_KEYSTORE, PARTNER1_CLIENT1_TRUSTSTORE, CRL_PEM),
Optional.of("certificate_unknown"),
Optional.empty()
},
{
"PKCS12 server Partner1 Client2 (revoked) -> PKCS12 client Partner2 Client1 FailedConnection",
false,
getSoftwareKeyStoreWrapper(
PARTNET1_CLIENT2_KEYSTORE, PARTNET1_CLIENT2_TRUSTSTORE, null),
getSoftwareKeyStoreWrapper(
PARTNER2_CLIENT1_KEYSTORE, PARTNER2_CLIENT1_TRUSTSTORE, CRL_PEM),
Optional.empty(),
Optional.of("Certificate revoked")
},
{
"PKCS12 server Partner2 Client1 -> PKCS12 client Partner1 Client2 (revoked) FailedConnection",
false,
getSoftwareKeyStoreWrapper(
PARTNER2_CLIENT1_KEYSTORE, PARTNER2_CLIENT1_TRUSTSTORE, CRL_PEM),
getSoftwareKeyStoreWrapper(
PARTNET1_CLIENT2_KEYSTORE, PARTNET1_CLIENT2_TRUSTSTORE, null),
Optional.of("Certificate revoked"),
Optional.of("certificate_unknown")
},
{
"PKCS12 server Partner2 Client2 (revoked) -> PKCS12 client Partner1 Client1 FailedConnection",
false,
getSoftwareKeyStoreWrapper(
PARTNER2_CLIENT2_KEYSTORE, PARTNER2_CLIENT2_TRUSTSTORE, null),
getSoftwareKeyStoreWrapper(
PARTNER1_CLIENT1_KEYSTORE, PARTNER1_CLIENT1_TRUSTSTORE, CRL_PEM),
Optional.empty(),
Optional.of("Certificate revoked"),
},
{
"PKCS12 server Partner1 Client1 -> PKCS12 client Partner2 Client2 (revoked) FailedConnection",
false,
getSoftwareKeyStoreWrapper(
PARTNER1_CLIENT1_KEYSTORE, PARTNER1_CLIENT1_TRUSTSTORE, CRL_PEM),
getSoftwareKeyStoreWrapper(
PARTNER2_CLIENT2_KEYSTORE, PARTNER2_CLIENT2_TRUSTSTORE, null),
Optional.of("Certificate revoked"),
Optional.of("certificate_unknown")
}
});
}
@BeforeEach
void init() {}
@AfterEach
void tearDown() {
if (client != null) {
client.stop();
}
if (server != null) {
server.stop();
}
}
private static Path toPath(final String path) throws Exception {
return null == path ? null : Path.of(TLSContextFactoryTest.class.getResource(path).toURI());
}
private static KeyStoreWrapper getHardwareKeyStoreWrapper(
final String config, final String crlLocation) {
try {
return new HardwareKeyStoreWrapper(keystorePassword, toPath(config), toPath(crlLocation));
} catch (final Exception e) {
// Not a mac, probably a production build. Full failure.
throw new PkiException("Failed to initialize hardware keystore", e);
}
}
private static KeyStoreWrapper getSoftwareKeyStoreWrapper(
final String jksKeyStore, final String trustStore, final String crl) {
try {
return new SoftwareKeyStoreWrapper(
KEYSTORE_TYPE_PKCS12,
toPath(jksKeyStore),
keystorePassword,
KEYSTORE_TYPE_PKCS12,
toPath(trustStore),
keystorePassword,
toPath(crl));
} catch (final Exception e) {
throw new PkiException("Failed to initialize software keystore", e);
}
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("softwareKeysData")
@DisabledOnOs(OS.MAC)
void testConnectionSoftwareKeys(
final String ignoredTestDescription,
final boolean testSuccess,
final KeyStoreWrapper serverKeyStoreWrapper,
final KeyStoreWrapper clientKeyStoreWrapper,
final Optional<String> serverFailureMessage,
final Optional<String> clientFailureMessage)
throws Exception {
testConnection(
testSuccess,
serverKeyStoreWrapper,
clientKeyStoreWrapper,
serverFailureMessage,
clientFailureMessage);
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("hardwareKeysData")
@DisabledOnOs(OS.MAC)
void testConnectionHardwareKeys(
final String ignoredTestDescription,
final boolean testSuccess,
final KeyStoreWrapper serverKeyStoreWrapper,
final KeyStoreWrapper clientKeyStoreWrapper,
final Optional<String> serverFailureMessage,
final Optional<String> clientFailureMessage)
throws Exception {
testConnection(
testSuccess,
serverKeyStoreWrapper,
clientKeyStoreWrapper,
serverFailureMessage,
clientFailureMessage);
}
private void testConnection(
final boolean testSuccess,
final KeyStoreWrapper serverKeyStoreWrapper,
final KeyStoreWrapper clientKeyStoreWrapper,
final Optional<String> serverFailureMessage,
final Optional<String> clientFailureMessage)
throws Exception {
final CountDownLatch serverLatch = new CountDownLatch(MAX_NUMBER_MESSAGES);
final CountDownLatch clientLatch = new CountDownLatch(MAX_NUMBER_MESSAGES);
server = startServer(serverKeyStoreWrapper, serverLatch);
client = startClient(server.port, clientKeyStoreWrapper, clientLatch);
if (testSuccess) {
client.getChannelFuture().channel().writeAndFlush(Unpooled.copyInt(0));
final boolean allMessagesServerExchanged = serverLatch.await(10, TimeUnit.SECONDS);
final boolean allMessagesClientExchanged = clientLatch.await(10, TimeUnit.SECONDS);
assertThat(allMessagesClientExchanged && allMessagesServerExchanged).isTrue();
} else {
try {
client.getChannelFuture().channel().writeAndFlush(Unpooled.copyInt(0)).sync();
serverLatch.await(2, TimeUnit.SECONDS);
assertThat(client.getChannelFuture().channel().isActive()).isFalse();
if (serverFailureMessage.isPresent()) {
assertThat(server.getCause()).isNotEmpty();
assertThat(server.getCause().get()).hasMessageContaining(serverFailureMessage.get());
} else {
assertThat(server.getCause()).isEmpty();
}
if (clientFailureMessage.isPresent()) {
assertThat(client.getCause()).isNotEmpty();
assertThat(client.getCause().get()).hasMessageContaining(clientFailureMessage.get());
} else {
assertThat(client.getCause()).isEmpty();
}
} catch (final Exception e) {
// NOOP
}
}
}
private Server startServer(final KeyStoreWrapper keyStoreWrapper, final CountDownLatch latch)
throws Exception {
final Server nettyServer = new Server(keystorePassword, keyStoreWrapper, latch);
nettyServer.start();
return nettyServer;
}
private Client startClient(
final int port, final KeyStoreWrapper keyStoreWrapper, final CountDownLatch latch)
throws Exception {
final Client nettyClient = new Client(port, keystorePassword, keyStoreWrapper, latch);
nettyClient.start();
return nettyClient;
}
static class MessageHandler extends ChannelInboundHandlerAdapter {
private final String id;
private final CountDownLatch latch;
private Throwable cause;
MessageHandler(final String id, final CountDownLatch latch) {
this.id = id;
this.latch = latch;
}
@Override
public void channelRead(final ChannelHandlerContext ctx, final Object msg)
throws InterruptedException {
final int message = ((ByteBuf) msg).readInt();
LOG.info("[" + id + "] Received message: " + message);
if (message < 2 * MAX_NUMBER_MESSAGES) {
final int replyMessage = message + 1;
ctx.writeAndFlush(Unpooled.copyInt(replyMessage)).sync();
LOG.info("[" + id + "] Sent message: " + replyMessage);
this.latch.countDown();
LOG.info("Remaining {}", this.latch.getCount());
}
}
@Override
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause)
throws Exception {
this.cause = cause;
}
public Optional<Throwable> getCause() {
return Optional.ofNullable(cause);
}
}
static class Client {
int port;
private final String keystorePassword;
private final KeyStoreWrapper keyStoreWrapper;
private final CountDownLatch latch;
private ChannelFuture channelFuture;
private final EventLoopGroup group = new NioEventLoopGroup();
private MessageHandler messageHandler;
ChannelFuture getChannelFuture() {
return channelFuture;
}
Client(
final int port,
final String keystorePassword,
final KeyStoreWrapper keyStoreWrapper,
final CountDownLatch latch) {
this.port = port;
this.keystorePassword = keystorePassword;
this.keyStoreWrapper = keyStoreWrapper;
this.latch = latch;
}
void start() throws Exception {
final Bootstrap b = new Bootstrap();
b.group(group);
b.channel(NioSocketChannel.class);
b.handler(
new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(final SocketChannel socketChannel) throws Exception {
final SslContext sslContext =
TLSContextFactory.getInstance(keystorePassword, keyStoreWrapper)
.createNettyClientSslContext();
final SslHandler sslHandler = sslContext.newHandler(socketChannel.alloc());
socketChannel.pipeline().addFirst("ssl", sslHandler);
messageHandler = new MessageHandler("Client", latch);
socketChannel.pipeline().addLast(messageHandler);
}
});
this.channelFuture = b.connect("127.0.0.1", this.port).sync();
}
void stop() {
group.shutdownGracefully();
messageHandler = null;
}
Optional<Throwable> getCause() {
return messageHandler != null ? messageHandler.getCause() : Optional.empty();
}
}
static class Server {
private int port;
private final String keystorePassword;
private final KeyStoreWrapper keyStoreWrapper;
private final CountDownLatch latch;
private Channel channel;
private final EventLoopGroup parentGroup = new NioEventLoopGroup();
private final EventLoopGroup childGroup = new NioEventLoopGroup();
private MessageHandler messageHandler;
Server(
final String keystorePassword,
final KeyStoreWrapper keyStoreWrapper,
final CountDownLatch latch) {
this.keystorePassword = keystorePassword;
this.keyStoreWrapper = keyStoreWrapper;
this.latch = latch;
}
void start() throws Exception {
final ServerBootstrap sb = new ServerBootstrap();
sb.group(parentGroup, childGroup)
.channel(NioServerSocketChannel.class)
.childHandler(
new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(final SocketChannel socketChannel) throws Exception {
final SslContext sslContext =
TLSContextFactory.getInstance(keystorePassword, keyStoreWrapper)
.createNettyServerSslContext();
final SslHandler sslHandler = sslContext.newHandler(channel.alloc());
socketChannel.pipeline().addFirst("ssl", sslHandler);
socketChannel
.pipeline()
.addLast(messageHandler = new MessageHandler("Server", latch));
}
});
final ChannelFuture cf = sb.bind(0).sync();
this.channel = cf.channel();
this.port = ((InetSocketAddress) channel.localAddress()).getPort();
}
void stop() {
childGroup.shutdownGracefully();
parentGroup.shutdownGracefully();
}
Optional<Throwable> getCause() {
return messageHandler != null ? messageHandler.getCause() : Optional.empty();
}
}
@Test
void dryRunDetector() {
assertThat(true)
.withFailMessage("This test is here so gradle --dry-run executes this class")
.isTrue();
}
}

@ -1,49 +0,0 @@
/*
* 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
*/
apply plugin: 'java-library'
jar {
archiveBaseName = 'besu-pki'
manifest {
attributes(
'Specification-Title': archiveBaseName,
'Specification-Version': project.version,
'Implementation-Title': archiveBaseName,
'Implementation-Version': calculateVersion(),
'Commit-Hash': getGitCommitDetails(40).hash
)
}
}
dependencies {
api 'org.slf4j:slf4j-api'
implementation 'com.google.guava:guava'
implementation 'io.tmio:tuweni-bytes'
implementation 'org.bouncycastle:bcpkix-jdk18on'
testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.mockito:mockito-core'
testImplementation 'org.mockito:mockito-junit-jupiter'
}
configurations { testArtifacts }
tasks.register('testJar', Jar) {
archiveBaseName = "${project.name}-test"
from sourceSets.test.output
}
artifacts { testArtifacts testJar }

@ -1,54 +0,0 @@
/*
* 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.pki;
/** The Pki exception. */
public class PkiException extends RuntimeException {
private static final long serialVersionUID = 1L;
/** Instantiates a new Pki exception. */
public PkiException() {
super();
}
/**
* Instantiates a new Pki exception.
*
* @param message the message
*/
public PkiException(final String message) {
super(message);
}
/**
* Instantiates a new Pki exception.
*
* @param message the message
* @param t the Throwable cause
*/
public PkiException(final String message, final Throwable t) {
super(message, t);
}
/**
* Instantiates a new Pki exception.
*
* @param t the Throwable cause
*/
public PkiException(final Throwable t) {
super(t);
}
}

@ -1,142 +0,0 @@
/*
* 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.pki.cms;
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.security.interfaces.ECPublicKey;
import java.security.spec.EllipticCurve;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.common.annotations.VisibleForTesting;
import org.apache.tuweni.bytes.Bytes;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DigestCalculatorProvider;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;
/** The Cms creator. */
public class CmsCreator {
static {
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(new BouncyCastleProvider());
}
}
private final String certificateAlias;
private final KeyStoreWrapper keyStore;
/**
* Instantiates a new Cms creator.
*
* @param keyStore the key store
* @param certificateAlias the certificate alias
*/
public CmsCreator(final KeyStoreWrapper keyStore, final String certificateAlias) {
this.keyStore = keyStore;
this.certificateAlias = certificateAlias;
}
/**
* Creates a CMS message with the content parameter, signed with the certificate with alias
* defined in the {@code CmsCreator} constructor. The certificate chain is also included so the
* recipient has the information needed to build a trusted certificate path when validating this
* message.
*
* @param contentToSign the content that will be signed and added to the message
* @return the CMS message bytes
*/
@SuppressWarnings("rawtypes")
public Bytes create(final Bytes contentToSign) {
try {
// Certificates that will be sent
final List<X509Certificate> x509Certificates =
Stream.of(keyStore.getCertificateChain(certificateAlias))
.map(X509Certificate.class::cast)
.collect(Collectors.toList());
final Store certs = new JcaCertStore(x509Certificates);
// Private key of the certificate that will sign the message
final PrivateKey privateKey = keyStore.getPrivateKey(certificateAlias);
final ContentSigner contentSigner =
new JcaContentSignerBuilder(
getPreferredSignatureAlgorithm(keyStore.getPublicKey(certificateAlias)))
.build(privateKey);
final CMSSignedDataGenerator cmsGenerator = new CMSSignedDataGenerator();
// Additional intermediate certificates for path building
cmsGenerator.addCertificates(certs);
final DigestCalculatorProvider digestCalculatorProvider =
new JcaDigestCalculatorProviderBuilder().setProvider("BC").build();
// The first certificate in the list (leaf certificate is the signer)
cmsGenerator.addSignerInfoGenerator(
new JcaSignerInfoGeneratorBuilder(digestCalculatorProvider)
.build(contentSigner, x509Certificates.get(0)));
// Add signed content
final CMSTypedData cmsData = new CMSProcessableByteArray(contentToSign.toArray());
final CMSSignedData cmsSignedData = cmsGenerator.generate(cmsData, false);
return Bytes.wrap(cmsSignedData.getEncoded());
} catch (final Exception e) {
throw new RuntimeException("Error creating CMS data", e);
}
}
/**
* Gets preferred signature algorithm for EC or RSA keys
*
* @param pub the public key
* @return the preferred signature algorithm
*/
@VisibleForTesting
public static String getPreferredSignatureAlgorithm(final PublicKey pub) {
switch (pub.getAlgorithm()) {
case "EC" -> {
final EllipticCurve curve = ((ECPublicKey) pub).getParams().getCurve();
return switch (curve.getField().getFieldSize()) {
case 224, 256 -> "SHA256withECDSA";
case 384 -> "SHA384withECDSA";
case 521 -> "SHA512withECDSA";
default -> throw new IllegalArgumentException("Elliptic curve not supported: " + curve);
};
}
case "RSA" -> {
return "SHA256WithRSAEncryption";
}
default ->
throw new UnsupportedOperationException(
"Private key algorithm not supported: " + pub.getAlgorithm());
}
}
}

@ -1,203 +0,0 @@
/*
* 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.pki.cms;
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper;
import java.security.Security;
import java.security.cert.CertPathBuilder;
import java.security.cert.CertPathBuilderException;
import java.security.cert.CertStore;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXRevocationChecker;
import java.security.cert.PKIXRevocationChecker.Option;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaCertStoreBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Store;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** The Cms validator. */
public class CmsValidator {
static {
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(new BouncyCastleProvider());
}
}
private static final Logger LOGGER = LoggerFactory.getLogger(CmsValidator.class);
private final KeyStoreWrapper truststore;
/**
* Instantiates a new Cms validator.
*
* @param truststore the truststore
*/
public CmsValidator(final KeyStoreWrapper truststore) {
this.truststore = truststore;
}
/**
* Verifies that a CMS message signed content matched the expected content, and that the message
* signer is from a certificate that is trusted (has permission to propose a block)
*
* @param cms the CMS message bytes
* @param expectedContent the expected signed content in the CMS message
* @return true, if the signed content matched the expected content and the signer's certificate
* is trusted, otherwise returns false.
*/
public boolean validate(final Bytes cms, final Bytes expectedContent) {
if (cms == null || cms.isEmpty()) {
return false;
}
try {
LOGGER.trace("Validating CMS message");
final CMSSignedData cmsSignedData =
new CMSSignedData(new CMSProcessableByteArray(expectedContent.toArray()), cms.toArray());
final X509Certificate signerCertificate = getSignerCertificate(cmsSignedData);
// Validate msg signature and content
if (!isSignatureValid(signerCertificate, cmsSignedData)) {
return false;
}
// Validate certificate trust
if (!isCertificateTrusted(signerCertificate, cmsSignedData)) {
return false;
}
return true;
} catch (final Exception e) {
throw new RuntimeException("Error validating CMS data", e);
}
}
@SuppressWarnings("unchecked")
private X509Certificate getSignerCertificate(final CMSSignedData cmsSignedData) {
try {
final Store<X509CertificateHolder> certificateStore = cmsSignedData.getCertificates();
// We don't expect more than one signer on the CMS data
if (cmsSignedData.getSignerInfos().size() != 1) {
throw new RuntimeException("Only one signer is expected on the CMS message");
}
final SignerInformation signerInformation =
cmsSignedData.getSignerInfos().getSigners().stream().findFirst().get();
// Find signer's certificate from CMS data
final Collection<X509CertificateHolder> signerCertificates =
certificateStore.getMatches(signerInformation.getSID());
final X509CertificateHolder certificateHolder = signerCertificates.stream().findFirst().get();
return new JcaX509CertificateConverter().getCertificate(certificateHolder);
} catch (final Exception e) {
throw new RuntimeException("Error retrieving signer certificate from CMS data", e);
}
}
private boolean isSignatureValid(
final X509Certificate signerCertificate, final CMSSignedData cmsSignedData) {
LOGGER.trace("Validating CMS signature");
try {
return cmsSignedData.verifySignatures(
sid -> new JcaSimpleSignerInfoVerifierBuilder().build(signerCertificate));
} catch (final CMSException e) {
return false;
}
}
private boolean isCertificateTrusted(
final X509Certificate signerCertificate, final CMSSignedData cmsSignedData) {
LOGGER.trace("Starting CMS certificate validation");
try {
final CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX");
// Define CMS signer certificate as the starting point of the path (leaf certificate)
final X509CertSelector targetConstraints = new X509CertSelector();
targetConstraints.setCertificate(signerCertificate);
// Set parameters for the certificate path building algorithm
final PKIXBuilderParameters params =
new PKIXBuilderParameters(truststore.getKeyStore(), targetConstraints);
// Adding CertStore with CRLs (if present, otherwise disabling revocation check)
createCRLCertStore(truststore)
.ifPresentOrElse(
CRLs -> {
params.addCertStore(CRLs);
PKIXRevocationChecker rc = (PKIXRevocationChecker) cpb.getRevocationChecker();
rc.setOptions(EnumSet.of(Option.PREFER_CRLS));
params.addCertPathChecker(rc);
},
() -> {
LOGGER.warn("No CRL CertStore provided. CRL validation will be disabled.");
params.setRevocationEnabled(false);
});
// Read certificates sent on the CMS message and adding it to the path building algorithm
final CertStore cmsCertificates =
new JcaCertStoreBuilder().addCertificates(cmsSignedData.getCertificates()).build();
params.addCertStore(cmsCertificates);
// Validate certificate path
try {
cpb.build(params);
return true;
} catch (final CertPathBuilderException cpbe) {
LOGGER.warn("Untrusted certificate chain", cpbe);
LOGGER.trace("Reason for failed validation", cpbe.getCause());
return false;
}
} catch (final Exception e) {
LOGGER.error("Error validating certificate chain");
throw new RuntimeException("Error validating certificate chain", e);
}
}
private Optional<CertStore> createCRLCertStore(final KeyStoreWrapper truststore) {
if (truststore.getCRLs() != null) {
try {
return Optional.of(
CertStore.getInstance(
"Collection", new CollectionCertStoreParameters(truststore.getCRLs())));
} catch (final Exception e) {
throw new RuntimeException("Error loading CRLs from Truststore", e);
}
} else {
return Optional.empty();
}
}
}

@ -1,303 +0,0 @@
/*
* 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.pki.config;
import static java.util.Objects.requireNonNull;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import java.util.stream.Stream;
import com.google.common.annotations.VisibleForTesting;
/** The Pki key store configuration. */
public class PkiKeyStoreConfiguration {
/** The constant DEFAULT_KEYSTORE_TYPE. */
public static String DEFAULT_KEYSTORE_TYPE = "PKCS12";
/** The constant DEFAULT_CERTIFICATE_ALIAS. */
public static String DEFAULT_CERTIFICATE_ALIAS = "validator";
private final String keyStoreType;
private final Path keyStorePath;
private final Path keyStorePasswordPath;
private final String certificateAlias;
private final String trustStoreType;
private final Path trustStorePath;
private final Path trustStorePasswordPath;
private final Optional<Path> crlFilePath;
/**
* Instantiates a new Pki key store configuration.
*
* @param keyStoreType the key store type
* @param keyStorePath the key store path
* @param keyStorePasswordPath the key store password path
* @param certificateAlias the certificate alias
* @param trustStoreType the trust store type
* @param trustStorePath the trust store path
* @param trustStorePasswordPath the trust store password path
* @param crlFilePath the crl file path
*/
public PkiKeyStoreConfiguration(
final String keyStoreType,
final Path keyStorePath,
final Path keyStorePasswordPath,
final String certificateAlias,
final String trustStoreType,
final Path trustStorePath,
final Path trustStorePasswordPath,
final Optional<Path> crlFilePath) {
this.keyStoreType = keyStoreType;
this.keyStorePath = keyStorePath;
this.keyStorePasswordPath = keyStorePasswordPath;
this.certificateAlias = certificateAlias;
this.trustStoreType = trustStoreType;
this.trustStorePath = trustStorePath;
this.trustStorePasswordPath = trustStorePasswordPath;
this.crlFilePath = crlFilePath;
}
/**
* Gets key store type.
*
* @return the key store type
*/
public String getKeyStoreType() {
return keyStoreType;
}
/**
* Gets key store path.
*
* @return the key store path
*/
public Path getKeyStorePath() {
return keyStorePath;
}
/**
* Gets key store password path.
*
* @return the key store password path
*/
@VisibleForTesting
public Path getKeyStorePasswordPath() {
return keyStorePasswordPath;
}
/**
* Gets key store password.
*
* @return the key store password
*/
public String getKeyStorePassword() {
return readPasswordFromFile(keyStorePasswordPath);
}
/**
* Gets certificate alias.
*
* @return the certificate alias
*/
public String getCertificateAlias() {
return certificateAlias;
}
/**
* Gets trust store type.
*
* @return the trust store type
*/
public String getTrustStoreType() {
return trustStoreType;
}
/**
* Gets trust store path.
*
* @return the trust store path
*/
public Path getTrustStorePath() {
return trustStorePath;
}
/**
* Gets trust store password path.
*
* @return the trust store password path
*/
@VisibleForTesting
public Path getTrustStorePasswordPath() {
return trustStorePasswordPath;
}
/**
* Gets trust store password.
*
* @return the trust store password
*/
public String getTrustStorePassword() {
return readPasswordFromFile(trustStorePasswordPath);
}
/**
* Gets CRL file path.
*
* @return the crl file path
*/
public Optional<Path> getCrlFilePath() {
return crlFilePath;
}
/** The Builder. */
public static final class Builder {
private String keyStoreType = DEFAULT_KEYSTORE_TYPE;
private Path keyStorePath;
private Path keyStorePasswordPath;
private String certificateAlias = DEFAULT_CERTIFICATE_ALIAS;
private String trustStoreType = DEFAULT_KEYSTORE_TYPE;
private Path trustStorePath;
private Path trustStorePasswordPath;
private Path crlFilePath;
/** Instantiates a new Builder. */
public Builder() {}
/**
* With key store type.
*
* @param keyStoreType the key store type
* @return the builder
*/
public Builder withKeyStoreType(final String keyStoreType) {
this.keyStoreType = keyStoreType;
return this;
}
/**
* With key store path.
*
* @param keyStorePath the key store path
* @return the builder
*/
public Builder withKeyStorePath(final Path keyStorePath) {
this.keyStorePath = keyStorePath;
return this;
}
/**
* With key store password path.
*
* @param keyStorePasswordPath the key store password path
* @return the builder
*/
public Builder withKeyStorePasswordPath(final Path keyStorePasswordPath) {
this.keyStorePasswordPath = keyStorePasswordPath;
return this;
}
/**
* With certificate alias.
*
* @param certificateAlias the certificate alias
* @return the builder
*/
public Builder withCertificateAlias(final String certificateAlias) {
this.certificateAlias = certificateAlias;
return this;
}
/**
* With trust store type.
*
* @param trustStoreType the trust store type
* @return the builder
*/
public Builder withTrustStoreType(final String trustStoreType) {
this.trustStoreType = trustStoreType;
return this;
}
/**
* With trust store path.
*
* @param trustStorePath the trust store path
* @return the builder
*/
public Builder withTrustStorePath(final Path trustStorePath) {
this.trustStorePath = trustStorePath;
return this;
}
/**
* With trust store password path.
*
* @param trustStorePasswordPath the trust store password path
* @return the builder
*/
public Builder withTrustStorePasswordPath(final Path trustStorePasswordPath) {
this.trustStorePasswordPath = trustStorePasswordPath;
return this;
}
/**
* With crl file path.
*
* @param filePath the file path
* @return the builder
*/
public Builder withCrlFilePath(final Path filePath) {
this.crlFilePath = filePath;
return this;
}
/**
* Build pki key store configuration.
*
* @return the pki key store configuration
*/
public PkiKeyStoreConfiguration build() {
requireNonNull(keyStoreType, "Key Store Type must not be null");
requireNonNull(keyStorePasswordPath, "Key Store password file must not be null");
return new PkiKeyStoreConfiguration(
keyStoreType,
keyStorePath,
keyStorePasswordPath,
certificateAlias,
trustStoreType,
trustStorePath,
trustStorePasswordPath,
Optional.ofNullable(crlFilePath));
}
}
private String readPasswordFromFile(final Path passwordFile) {
try (final Stream<String> fileStream = Files.lines(passwordFile)) {
return fileStream.findFirst().orElseThrow(() -> errorReadingFileException(passwordFile));
} catch (final IOException e) {
throw errorReadingFileException(passwordFile);
}
}
private RuntimeException errorReadingFileException(final Path path) {
return new RuntimeException(String.format("Unable to read keystore password from %s", path));
}
}

@ -1,53 +0,0 @@
/*
* 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.pki.crl;
import org.hyperledger.besu.pki.PkiException;
import java.io.FileInputStream;
import java.nio.file.Paths;
import java.security.cert.CertStore;
import java.security.cert.CertificateFactory;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.X509CRL;
import java.util.List;
import java.util.stream.Collectors;
/** The CRL util. */
public class CRLUtil {
/** Default constructor */
private CRLUtil() {}
/**
* Load CRLs cert store.
*
* @param path the path
* @return the cert store
*/
public static CertStore loadCRLs(final String path) {
try {
final List<X509CRL> crls =
CertificateFactory.getInstance("X509")
.generateCRLs(new FileInputStream(Paths.get(path).toFile()))
.stream()
.map(X509CRL.class::cast)
.collect(Collectors.toList());
return CertStore.getInstance("Collection", new CollectionCertStoreParameters(crls));
} catch (Exception e) {
throw new PkiException("Error loading CRL file " + path, e);
}
}
}

@ -1,68 +0,0 @@
/*
* 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.pki.keystore;
import org.hyperledger.besu.pki.PkiException;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Path;
import java.security.cert.CertificateFactory;
import java.security.cert.X509CRL;
import java.util.Collection;
import java.util.stream.Collectors;
/** The Abstract key store wrapper. */
public abstract class AbstractKeyStoreWrapper implements KeyStoreWrapper {
private static final String X_509 = "X.509";
private final Collection<X509CRL> crls;
/**
* Instantiates a new Abstract key store wrapper.
*
* @param crlLocation the crl location
*/
protected AbstractKeyStoreWrapper(final Path crlLocation) {
super();
if (null == crlLocation) {
this.crls = null;
} else {
try (InputStream stream = new FileInputStream(crlLocation.toFile())) {
this.crls =
CertificateFactory.getInstance(X_509).generateCRLs(stream).stream()
.map(X509CRL.class::cast)
.collect(Collectors.toList());
} catch (final Exception e) {
throw new PkiException("Failed to initialize software truststore", e);
}
}
}
/**
* Instantiates a new Abstract key store wrapper.
*
* @param crls the collection of X509CRL instances
*/
protected AbstractKeyStoreWrapper(final Collection<X509CRL> crls) {
this.crls = crls;
}
@Override
public Collection<X509CRL> getCRLs() {
return crls;
}
}

@ -1,210 +0,0 @@
/*
* 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.pki.keystore;
import org.hyperledger.besu.pki.PkiException;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Path;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509CRL;
import java.util.Collection;
import java.util.Optional;
import java.util.Properties;
import java.util.stream.Stream;
import com.google.common.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Creates an instance of this class which is backed by a PKCS#11 keystore, such as a software
* (emulated) HSM or a physical/cloud HSM (see <a href=
* "https://docs.oracle.com/en/java/javase/11/security/pkcs11-reference-guide1.html">here</a>
*/
public class HardwareKeyStoreWrapper extends AbstractKeyStoreWrapper {
private static final Logger LOG = LoggerFactory.getLogger(HardwareKeyStoreWrapper.class);
private static final String pkcs11Provider = "SunPKCS11";
private final KeyStore keystore;
private final transient char[] keystorePassword;
private final java.security.Provider provider;
/**
* Instantiates a new Hardware key store wrapper.
*
* @param keystorePassword the keystore password
* @param provider the provider
* @param crlLocation the crl location
*/
public HardwareKeyStoreWrapper(
final String keystorePassword, final Provider provider, final Path crlLocation) {
super(crlLocation);
try {
if (provider == null) {
throw new IllegalArgumentException("Provider is null");
}
this.keystorePassword = keystorePassword.toCharArray();
this.provider = provider;
if (Security.getProvider(provider.getName()) == null) {
Security.addProvider(provider);
}
keystore = KeyStore.getInstance(KeyStoreWrapper.KEYSTORE_TYPE_PKCS11, provider);
keystore.load(null, this.keystorePassword);
} catch (final Exception e) {
throw new PkiException("Failed to initialize HSM keystore", e);
}
}
/**
* Instantiates a new Hardware key store wrapper.
*
* @param keystorePassword the keystore password
* @param config the config
* @param crlLocation the CRL location
*/
public HardwareKeyStoreWrapper(
final String keystorePassword, final Path config, final Path crlLocation) {
super(crlLocation);
try {
if (keystorePassword == null) {
throw new IllegalArgumentException("Keystore password is null");
}
final Properties properties = new Properties();
final File configFile = config.toFile();
try (InputStream ins = new FileInputStream(configFile)) {
properties.load(ins);
}
final String name = properties.getProperty("name");
this.keystorePassword = keystorePassword.toCharArray();
final Optional<Provider> existingProvider =
Stream.of(Security.getProviders())
.filter(p -> p.getName().equals(String.format("%s-%s", pkcs11Provider, name)))
.findAny();
if (existingProvider.isPresent()) {
provider = existingProvider.get();
} else {
provider = getPkcs11Provider(configFile.getAbsolutePath());
Security.addProvider(provider);
}
keystore = KeyStore.getInstance(KeyStoreWrapper.KEYSTORE_TYPE_PKCS11, provider);
keystore.load(null, this.keystorePassword);
} catch (final Exception e) {
throw new PkiException("Failed to initialize HSM keystore", e);
}
}
/**
* Instantiates a new Hardware key store wrapper.
*
* @param crls the collection of X509CRL crls
* @param keystore the keystore
* @param password the password
*/
@VisibleForTesting
HardwareKeyStoreWrapper(
final Collection<X509CRL> crls, final KeyStore keystore, final String password) {
super(crls);
this.keystore = keystore;
this.keystorePassword = password.toCharArray();
this.provider = null;
}
@Override
public PrivateKey getPrivateKey(final String keyAlias) {
try {
LOG.debug("Retrieving private key for alias: {}", keyAlias);
return (PrivateKey) keystore.getKey(keyAlias, this.keystorePassword);
} catch (final Exception e) {
throw new PkiException("Failed to get key: " + keyAlias, e);
}
}
@Override
public PublicKey getPublicKey(final String keyAlias) {
try {
LOG.debug("Retrieving public key for alias: {}", keyAlias);
final Certificate certificate = keystore.getCertificate(keyAlias);
return (certificate != null) ? certificate.getPublicKey() : null;
} catch (final Exception e) {
throw new PkiException("Failed to get key: " + keyAlias, e);
}
}
@Override
public Certificate getCertificate(final String certificateAlias) {
try {
LOG.debug("Retrieving certificate for alias: {}", certificateAlias);
return keystore.getCertificate(certificateAlias);
} catch (final Exception e) {
throw new PkiException("Failed to get certificate: " + certificateAlias, e);
}
}
@Override
public Certificate[] getCertificateChain(final String certificateAlias) {
try {
LOG.debug("Retrieving certificate chain for alias: {}", certificateAlias);
return keystore.getCertificateChain(certificateAlias);
} catch (final Exception e) {
throw new PkiException("Failed to certificate chain for alias: " + certificateAlias, e);
}
}
@Override
public KeyStore getKeyStore() {
return keystore;
}
@Override
public KeyStore getTrustStore() {
return keystore;
}
private Provider getPkcs11Provider(final String config) {
final Provider provider = Security.getProvider(pkcs11Provider);
if (null == provider) {
throw new IllegalArgumentException("Unable to load PKCS11 provider configuration.");
} else {
return provider.configure(config);
}
}
/**
* Gets PKCS11 provider.
*
* @param config the config
* @return the PKCS11 provider
*/
@VisibleForTesting
public Provider getPkcs11ProviderForConfig(final String config) {
return getPkcs11Provider(config);
}
}

@ -1,88 +0,0 @@
/*
* 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.pki.keystore;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509CRL;
import java.util.Collection;
/** The interface Key store wrapper. */
public interface KeyStoreWrapper {
/** The constant KEYSTORE_TYPE_JKS. */
String KEYSTORE_TYPE_JKS = "JKS";
/** The constant KEYSTORE_TYPE_PKCS11. */
String KEYSTORE_TYPE_PKCS11 = "PKCS11";
/** The constant KEYSTORE_TYPE_PKCS12. */
String KEYSTORE_TYPE_PKCS12 = "PKCS12";
/**
* Gets key store.
*
* @return the key store
*/
KeyStore getKeyStore();
/**
* Gets trust store.
*
* @return the trust store
*/
KeyStore getTrustStore();
/**
* Gets private key.
*
* @param keyAlias the key alias
* @return the private key
*/
PrivateKey getPrivateKey(String keyAlias);
/**
* Gets public key.
*
* @param keyAlias the key alias
* @return the public key
*/
PublicKey getPublicKey(String keyAlias);
/**
* Gets certificate.
*
* @param certificateAlias the certificate alias
* @return the certificate
*/
Certificate getCertificate(String certificateAlias);
/**
* Get certificate chain array.
*
* @param certificateAlias the certificate alias
* @return the certificate [ ]
*/
Certificate[] getCertificateChain(String certificateAlias);
/**
* Gets CRLs.
*
* @return the CRLs
*/
Collection<X509CRL> getCRLs();
}

@ -1,269 +0,0 @@
/*
* 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.pki.keystore;
import org.hyperledger.besu.pki.PkiException;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509CRL;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import com.google.common.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** The Software key store wrapper. */
public class SoftwareKeyStoreWrapper extends AbstractKeyStoreWrapper {
private static final Logger LOG = LoggerFactory.getLogger(SoftwareKeyStoreWrapper.class);
private final KeyStore keystore;
private final transient char[] keystorePassword;
private KeyStore truststore;
private transient char[] truststorePassword;
private final Map<String, PrivateKey> cachedPrivateKeys = new HashMap<>();
private final Map<String, PublicKey> cachedPublicKeys = new HashMap<>();
private final Map<String, Certificate> cachedCertificates = new HashMap<>();
/**
* Instantiates a new Software key store wrapper.
*
* @param keystoreType the keystore type
* @param keystoreLocation the keystore location
* @param keystorePassword the keystore password
* @param crlLocation the crl location
*/
public SoftwareKeyStoreWrapper(
final String keystoreType,
final Path keystoreLocation,
final String keystorePassword,
final Path crlLocation) {
this(keystoreType, keystoreLocation, keystorePassword, null, null, null, crlLocation);
}
/**
* Instantiates a new Software key store wrapper.
*
* @param keystoreType the keystore type
* @param keystoreLocation the keystore location
* @param keystorePassword the keystore password
* @param truststoreType the truststore type
* @param truststoreLocation the truststore location
* @param truststorePassword the truststore password
* @param crlLocation the crl location
*/
public SoftwareKeyStoreWrapper(
final String keystoreType,
final Path keystoreLocation,
final String keystorePassword,
final String truststoreType,
final Path truststoreLocation,
final String truststorePassword,
final Path crlLocation) {
super(crlLocation);
if (keystorePassword == null) {
throw new IllegalArgumentException("Keystore password is null");
}
this.keystorePassword = keystorePassword.toCharArray();
try (InputStream stream = new FileInputStream(keystoreLocation.toFile())) {
keystore = KeyStore.getInstance(keystoreType);
keystore.load(stream, this.keystorePassword);
} catch (final Exception e) {
throw new PkiException("Failed to initialize software keystore: " + keystoreLocation, e);
}
if (truststoreType != null && truststoreLocation != null) {
this.truststorePassword =
(truststorePassword != null) ? truststorePassword.toCharArray() : null;
try (InputStream stream = new FileInputStream(truststoreLocation.toFile())) {
truststore = KeyStore.getInstance(truststoreType);
truststore.load(stream, this.truststorePassword);
} catch (final Exception e) {
throw new PkiException(
"Failed to initialize software truststore: " + truststoreLocation, e);
}
}
}
/**
* Instantiates a new Software key store wrapper.
*
* @param keystore the keystore
* @param keystorePassword the keystore password
* @param truststore the truststore
* @param truststorePassword the truststore password
*/
@VisibleForTesting
public SoftwareKeyStoreWrapper(
final KeyStore keystore,
final String keystorePassword,
final KeyStore truststore,
final String truststorePassword) {
super((Path) null);
this.keystore = keystore;
this.keystorePassword = keystorePassword.toCharArray();
this.truststore = truststore;
this.truststorePassword = truststorePassword.toCharArray();
}
/**
* Instantiates a new Software key store wrapper.
*
* @param crls the collection of X509CRL crls
* @param keystore the keystore
* @param keystorePassword the keystore password
*/
@VisibleForTesting
public SoftwareKeyStoreWrapper(
final Collection<X509CRL> crls, final KeyStore keystore, final String keystorePassword) {
super(crls);
this.keystore = keystore;
this.keystorePassword = keystorePassword.toCharArray();
this.truststore = null;
this.truststorePassword = null;
}
@Override
public PrivateKey getPrivateKey(final String keyAlias) {
LOG.debug("Retrieving private key for alias: {}", keyAlias);
return (PrivateKey) getKey(keyAlias, PrivateKey.class, cachedPrivateKeys);
}
@Override
public PublicKey getPublicKey(final String keyAlias) {
LOG.debug("Retrieving public key for alias: {}", keyAlias);
return (PublicKey) getKey(keyAlias, PublicKey.class, cachedPublicKeys);
}
@Override
public Certificate getCertificate(final String certificateAlias) {
try {
LOG.debug("Retrieving certificate for alias: {}", certificateAlias);
Certificate certificate = cachedCertificates.get(certificateAlias);
if (certificate == null) {
LOG.debug("Certificate alias: {} not cached", certificateAlias);
certificate = keystore.getCertificate(certificateAlias);
if (certificate == null && truststore != null) {
certificate = truststore.getCertificate(certificateAlias);
}
if (certificate != null) {
LOG.debug("Certificate alias: {} found in keystore/truststore", certificateAlias);
cachedCertificates.put(certificateAlias, certificate);
cachedPublicKeys.put(certificateAlias, certificate.getPublicKey());
return certificate;
} else {
LOG.warn("Certificate alias: {} not found in keystore/truststore", certificateAlias);
}
}
return certificate;
} catch (final Exception e) {
throw new PkiException("Failed to get certificate: " + certificateAlias, e);
}
}
@Override
public Certificate[] getCertificateChain(final String certificateAlias) {
try {
LOG.debug("Retrieving certificate chain for alias: {}", certificateAlias);
Certificate[] certificateChain = keystore.getCertificateChain(certificateAlias);
if (certificateChain == null && truststore != null) {
certificateChain = truststore.getCertificateChain(certificateAlias);
}
return certificateChain;
} catch (final Exception e) {
throw new PkiException(
"Failed to retrieve certificate chain for alias: " + certificateAlias, e);
}
}
private Key getKey(
final String keyAlias,
final Class<? extends Key> keyTypeClass,
final Map<String, ? extends Key> keyCache) {
Key cachedKey = keyCache.get(keyAlias);
if (cachedKey == null) {
LOG.debug("Key alias: {} not cached", keyAlias);
try {
cachedKey = loadAndCacheKey(this.keystore, this.keystorePassword, keyAlias, keyTypeClass);
if (cachedKey == null) {
cachedKey =
loadAndCacheKey(this.truststore, this.truststorePassword, keyAlias, keyTypeClass);
}
} catch (final Exception e) {
throw new PkiException("Failed to get key: " + keyAlias, e);
}
}
return cachedKey;
}
@Override
public KeyStore getKeyStore() {
return keystore;
}
@Override
public KeyStore getTrustStore() {
return truststore;
}
private Key loadAndCacheKey(
final KeyStore keystore,
final char[] keystorePassword,
final String keyAlias,
final Class<? extends Key> keyTypeClass)
throws GeneralSecurityException {
if (keystore != null && keystore.containsAlias(keyAlias)) {
final Key key = keystore.getKey(keyAlias, keystorePassword);
if (key != null) {
LOG.debug("Key alias: {} found in keystore/truststore", keyAlias);
if (key instanceof PrivateKey && PrivateKey.class.isAssignableFrom(keyTypeClass)) {
cachedPrivateKeys.put(keyAlias, (PrivateKey) key);
return key;
} else if (key instanceof PublicKey && PublicKey.class.isAssignableFrom(keyTypeClass)) {
cachedPublicKeys.put(keyAlias, (PublicKey) key);
return key;
}
}
if (PublicKey.class.isAssignableFrom(keyTypeClass)) {
final Certificate certificate = getCertificate(keyAlias);
if (certificate != null) {
return certificate.getPublicKey();
}
}
}
LOG.warn("Key alias: {} not found in keystore/truststore", keyAlias);
return null;
}
}

@ -1,217 +0,0 @@
/*
* 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.pki.util;
import org.hyperledger.besu.pki.cms.CmsCreator;
import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.cert.CRLException;
import java.security.cert.CRLReason;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.security.spec.ECGenParameterSpec;
import java.sql.Date;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Collection;
import java.util.Random;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.cert.X509CRLHolder;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v2CRLBuilder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CRLConverter;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.X509KeyUsage;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
/*
This class provides utility method for creating certificates used on tests.
Based on https://stackoverflow.com/a/18648284/5021783
*/
public class TestCertificateUtils {
static {
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(new BouncyCastleProvider());
}
}
public enum Algorithm {
RSA,
EC
}
public static KeyPair createKeyPair(final Algorithm algorithm) {
try {
@SuppressWarnings("InsecureCryptoUsage")
final KeyPairGenerator kpg = KeyPairGenerator.getInstance(algorithm.name());
if (algorithm == Algorithm.EC) {
kpg.initialize(new ECGenParameterSpec("secp256r1"));
}
return kpg.generateKeyPair();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Error creating KeyPair", e);
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
}
}
public static X509Certificate createSelfSignedCertificate(
final String name, final Instant notBefore, final Instant notAfter, final KeyPair keyPair) {
try {
final String signatureAlgorithm =
CmsCreator.getPreferredSignatureAlgorithm(keyPair.getPublic());
final ContentSigner signer =
new JcaContentSignerBuilder(signatureAlgorithm).build(keyPair.getPrivate());
final X509v3CertificateBuilder certificateBuilder =
new JcaX509v3CertificateBuilder(
new X500Name("CN=" + name),
new BigInteger(32, new Random()),
Date.from(notBefore),
Date.from(notAfter),
new X500Name("CN=" + name),
keyPair.getPublic())
.addExtension(
Extension.authorityKeyIdentifier,
false,
new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(keyPair.getPublic()))
.addExtension(
Extension.subjectKeyIdentifier,
false,
new JcaX509ExtensionUtils().createSubjectKeyIdentifier(keyPair.getPublic()))
.addExtension(
Extension.basicConstraints,
false,
new BasicConstraints(true)) // true if it is allowed to sign other certs
.addExtension(
Extension.keyUsage,
true,
new X509KeyUsage(X509KeyUsage.keyCertSign | X509KeyUsage.cRLSign));
final X509CertificateHolder certHolder = certificateBuilder.build(signer);
return new JcaX509CertificateConverter()
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
.getCertificate(certHolder);
} catch (final Exception e) {
throw new RuntimeException("Error creating CA certificate", e);
}
}
public static X509Certificate issueCertificate(
final X509Certificate issuer,
final KeyPair issuerKeyPair,
final String subject,
final Instant notBefore,
final Instant notAfter,
final KeyPair keyPair,
final boolean isCa) {
try {
final String signatureAlgorithm =
CmsCreator.getPreferredSignatureAlgorithm(keyPair.getPublic());
final ContentSigner signer =
new JcaContentSignerBuilder(signatureAlgorithm).build(issuerKeyPair.getPrivate());
final X509v3CertificateBuilder certificateBuilder =
new JcaX509v3CertificateBuilder(
issuer,
new BigInteger(32, new Random()),
Date.from(notBefore),
Date.from(notAfter),
new X500Name("CN=" + subject),
keyPair.getPublic())
.addExtension(
Extension.authorityKeyIdentifier,
false,
new JcaX509ExtensionUtils()
.createAuthorityKeyIdentifier(issuerKeyPair.getPublic()))
.addExtension(
Extension.basicConstraints,
false,
new BasicConstraints(isCa)) // true if it is allowed to sign other certs
.addExtension(
Extension.keyUsage,
true,
new X509KeyUsage(
X509KeyUsage.digitalSignature
| X509KeyUsage.nonRepudiation
| X509KeyUsage.keyEncipherment
| X509KeyUsage.dataEncipherment
| X509KeyUsage.cRLSign
| X509KeyUsage.keyCertSign));
final X509CertificateHolder certHolder = certificateBuilder.build(signer);
return new JcaX509CertificateConverter()
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
.getCertificate(certHolder);
} catch (final Exception e) {
throw new RuntimeException("Error creating certificate", e);
}
}
public static X509CRL createCRL(
final X509Certificate issuer,
final KeyPair issuerKeyPair,
final Collection<X509Certificate> revokedCertificates) {
try {
final X509CertificateHolder x509CertificateHolder =
new X509CertificateHolder(issuer.getEncoded());
final X509v2CRLBuilder crlBuilder =
new X509v2CRLBuilder(x509CertificateHolder.getSubject(), Date.from(Instant.now()));
revokedCertificates.forEach(
c ->
crlBuilder.addCRLEntry(
c.getSerialNumber(), Date.from(Instant.now()), CRLReason.UNSPECIFIED.ordinal()));
crlBuilder.setNextUpdate(Date.from(Instant.now().plus(1, ChronoUnit.DAYS)));
final String signatureAlgorithm =
CmsCreator.getPreferredSignatureAlgorithm(issuerKeyPair.getPublic());
final ContentSigner signer =
new JcaContentSignerBuilder(signatureAlgorithm).build(issuerKeyPair.getPrivate());
final X509CRLHolder crlHolder = crlBuilder.build(signer);
return new JcaX509CRLConverter()
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
.getCRL(crlHolder);
} catch (OperatorCreationException
| CRLException
| CertificateEncodingException
| IOException e) {
throw new RuntimeException(e);
}
}
}

@ -1,27 +0,0 @@
-----BEGIN X509 CRL-----
MIICBDCB7QIBATANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCVVMxCzAJBgNV
BAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJBgNVBAoMAk1DMQ0wCwYDVQQLDARyb290
MRMwEQYDVQQDDApwYXJ0bmVyMWNhMSYwJAYJKoZIhvcNAQkBFhdwYXJ0bmVyMWNh
QHBhcnRuZXIxLmNvbRcNMjEwNjA3MTcwNjAwWhcNMjIwNjA3MTcwNjAwWjAnMCUC
FGltgEkvXupxY562dERH8+uKOf89Fw0yMTA2MDcxNzA2MDBaoA4wDDAKBgNVHRQE
AwIBADANBgkqhkiG9w0BAQsFAAOCAQEABF/7Kq+byYi/bRoftL8xqgSGcaLVuCOF
BZVZXDKjyYfISwBqbvPSqtIvnFO1ewicgD7dNIZwWcQ9Kx7OOz4BA6Pe8YPtiBfp
HZMabT8BS2eLePvViGumY7PTo3oIk3yXylOtzMDo59WQhCH/0vp5xjzJC+VFex/W
p/an5ii1y3Q1FpEZNer6jpU0xJEJ2mCaGT/zuj6Mg1awWqmmYce3BahZeCNj8Wyx
GIy8bGUjOdJyp99rAF9euCZ45pAjI12sg9lhPIVkp3Wnoy3La4Yj219Elc3MbJvF
8GEFEmZ0Lm5Ze/EG5VyLB+wRpggeSJTc20i/eGWdaWg8AEukCgMdCg==
-----END X509 CRL-----
-----BEGIN X509 CRL-----
MIICLDCCARQCAQEwDQYJKoZIhvcNAQELBQAwgYExCzAJBgNVBAYTAlVTMQswCQYD
VQQIDAJDQTEMMAoGA1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9v
dDETMBEGA1UEAwwKcGFydG5lcjJjYTEmMCQGCSqGSIb3DQEJARYXcGFydG5lcjJj
YUBwYXJ0bmVyMi5jb20XDTIxMDYwNzE3MDYwMFoXDTIyMDYwNzE3MDYwMFowTjAl
AhRpbYBJL17qcWOetnRER/Prijn/PRcNMjEwNjA3MTcwNjAwWjAlAhR+2Aa1zeVQ
jbXFGnXFu53h4vZEahcNMjEwNjA3MTcwNjAwWqAOMAwwCgYDVR0UBAMCAQEwDQYJ
KoZIhvcNAQELBQADggEBAFXQOMk+6FDP8bm9TGK079IHojhooipo+9x3I1y/kUhH
XY7xuyTXOvzv14//xenDuryIjSAC8pyqbls+DcUXkmGZ/nIWugtMykGLNgqqo/Oe
pfoUSXRJP7CtvfHa4ejfr3q1t5MXfM3nqBQumu65slWjDFtE6mZF4ANcsIlsNQ10
GTkDIdDHgUWxmZlBzTkoofvYspixuUptpJfl5eei9SDA+T1uADKnjARkxVv8xeYi
QwTp6jVYq6YKc9z0l1UMadnFQz8osk7QNypWnsrD0+iBB1if8ikJwy+8BWayTkgQ
tWLFT4n/c1m/wYzSclvZUUOxkkkE4Q9fZ3ReCADC+bQ=
-----END X509 CRL-----

@ -1,6 +0,0 @@
name = NSScrypto-invalidpartner1client1
nssSecmodDirectory = ./src/test/resources/keystore/invalidpartner1client1/nssdb
nssDbMode = readOnly
nssModule = keystore

@ -1,72 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEFDCCAvygAwIBAgIUaZCzBtI9osbhHtrNGSQLldSCSHkwDQYJKoZIhvcNAQEL
BQAwgYYxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDU0ZPMQsw
CQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEXMBUGA1UEAwwOaW52YWxpZGludGVy
Y2ExJzAlBgkqhkiG9w0BCQEWGGludmFsaWRpbnRlcmNhQGFkbWluLmNvbTAgFw0y
MTA2MDcxNzA1NTJaGA8yMTIxMDUxNDE3MDU1MlowgZYxCzAJBgNVBAYTAlVTMQsw
CQYDVQQIDAJDQTEMMAoGA1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwE
cm9vdDEaMBgGA1UEAwwRaW52YWxpZHBhcnRuZXIxY2ExNDAyBgkqhkiG9w0BCQEW
JWludmFsaWRwYXJ0bmVyMWNhQGludmFsaWRwYXJ0bmVyMS5jb20wggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDEMKBBPhzkvg+icZoRsN8CW2tlB4RZXo3C
apaQu2oJdEIqyKMRx86Uk7mRsW4rNWSbOjQwfCVsvhkUdriqBD+DfkzE03KKmhmL
hs2aC+ICb31aGyEvfWYFmKckY4zO8ptObaddWUZt27aie5vOzutB9n+oBmZMezd1
xc4dwOO+MzC92Ay3DIxw52SzGiywPGn3gfNWZ5NGvWM1poV4SwTi/eJXF/lwU9aY
Hl/+XOQ5/PJrIiQKGbBaywoOwYUU3FReosgCFVwDadnsj4ma++TKi/U7GQTcA01B
1F42sZx1vmLJC68jAyDJylAEtUZxiGs8LQ/S8B1zXBvdfiYW7RQfAgMBAAGjZjBk
MB0GA1UdDgQWBBQswNKqcoGkBJOL6/iCkqmNYsyypzAfBgNVHSMEGDAWgBRZVeo2
o+J44Ie43gS6L4tG3S0CaTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQE
AwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAUu60om2Fcx7h5C+bVmmBUhMDbnkWO9pa
lmEhmeuRrrmvSj/Ny6vmAmy9XOpox2PWMO5AndCIChLX697M4HskxIXCYhZzhjHE
x85WtmRjZAxdBA7vhgA6KIz58BJ6PmmJ3nYwc9dpyMthuMH74FcjfgsBL/1UalLI
26WtNMqEr+qK/drrlKpGHb1TjB3eWC1OPAwusgkw4uQBzKGHUZKxsVlaQ8jNkLdq
t31kMk770wXPh57N1tMn+gF21kACbkk0L4os+5AknYXWUS1A546I1TiEKmbKktPa
SdZIUT2AdIpZl4XMR5DZXBhMw8i/XyNfU6mW4b7TRt+QHU8l8ao47Q==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIECDCCAvCgAwIBAgIUK5+/p9u9ZYQuD9obuRHeJx0msBgwDQYJKoZIhvcNAQEL
BQAwgYoxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDU0ZPMQsw
CQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEcMBoGA1UEAwwTcm9vdGludmFsaWRj
YS5hZG1pbjEmMCQGCSqGSIb3DQEJARYXcm9vdGludmFsaWRjYUBhZG1pbi5jb20w
IBcNMjEwNjA3MTcwNTUyWhgPMjEyMTA1MTQxNzA1NTJaMIGGMQswCQYDVQQGEwJV
UzELMAkGA1UECAwCQ0ExDDAKBgNVBAcMA1NGTzELMAkGA1UECgwCTUMxDTALBgNV
BAsMBHJvb3QxFzAVBgNVBAMMDmludmFsaWRpbnRlcmNhMScwJQYJKoZIhvcNAQkB
FhhpbnZhbGlkaW50ZXJjYUBhZG1pbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQDNNU2p6MImjkrboq5MG7x422jISEYA9Zi/AMruUlQIXYwNUClc
yhalIPaToNRDBZ1mxj1uhdS/bxbAGxfO7EDQAcTGzIMhlkC+i/zLTSXTsoHjmgrt
5ZNQsc2Ok/a4aMpDUxZIx480Gm1GWEn5wrZpKJPdPnwwOg8tcjT4FCxI3CsMYQqb
UOR3iJn9IRyqTc1M/LCt5rYsd3slXVMnEOU5iu4UHJaNzKLlfsnB2LsdVqGqKA2e
nc6xdui+iJh81dqX/0RVUmyz4lDvhw8qfE58WAo4iIcpjBDcS8GPwt7WBF5KR120
HWF3HErVOsra/eVPK3iZU5vvWuU+zQ8pAm5DAgMBAAGjZjBkMB0GA1UdDgQWBBRZ
Veo2o+J44Ie43gS6L4tG3S0CaTAfBgNVHSMEGDAWgBS5ftf0c7cpwPnkG0MaBaV5
jXxrdzASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
9w0BAQsFAAOCAQEAjnY1t9Pt8DxhExpqnLBLkhGeg+upWQutTsvW+JMowPw+rX3H
m7mRKDkGl98Ol9m/6Iwx4kjgNz/bFx9flgJTYKvLE+yK/Jg4cizMjE4s9CzBA9ic
R20L0MrRS3w8ae6IXXDZaaZvwmUqxYOCChr1mXslP59EXPPeTbQa2asTAz5sYAFV
btPAjNa0T3KGcSbKyfZj3kAmNBFXrpyS0FcEQCt/u3USx1zGF1YuPGte0VBxtYw1
S/6DAeff+3rA9FAXXoG4qu+ZKu2kYydyJJPborTtJ3A/ATJmcJL2KW6ADHRK7rn1
NLj25w6mQoSRhoOLWHe+oWNF5nMO1SmMzfwlEQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID+TCCAuGgAwIBAgIUMcRYNxIDRzqdAgyjxeKuyrSVsscwDQYJKoZIhvcNAQEL
BQAwgYoxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDU0ZPMQsw
CQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEcMBoGA1UEAwwTcm9vdGludmFsaWRj
YS5hZG1pbjEmMCQGCSqGSIb3DQEJARYXcm9vdGludmFsaWRjYUBhZG1pbi5jb20w
IBcNMjEwNjA3MTcwNTUyWhgPMjEyMTA1MTQxNzA1NTJaMIGKMQswCQYDVQQGEwJV
UzELMAkGA1UECAwCQ0ExDDAKBgNVBAcMA1NGTzELMAkGA1UECgwCTUMxDTALBgNV
BAsMBHJvb3QxHDAaBgNVBAMME3Jvb3RpbnZhbGlkY2EuYWRtaW4xJjAkBgkqhkiG
9w0BCQEWF3Jvb3RpbnZhbGlkY2FAYWRtaW4uY29tMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAzmtt2EEdHNucUr8lZt8owINf9dSmCcpt663rnj833TO1
mCdKdmZvQYzgvdfVCLqonj5CaHts4GCyh3PeHxU+zqjEWxPbZCSkITKOtn3AblTJ
n4yFGpV6eIuGRFSL6TAaSPOyt59ZIFfSn5HDpVtET2/1hKRjjEnWhKy1pIG2J/mp
BaXO7QJtJyTbYdXm2AXorQChbX8T5J965wl4k/xLGrHtRcvaDeZsy9TdtYLseC78
bLFVwi7gAu3S9R6u9AuoVEn3rSZXaF+wSkH0GTX8rP049wQ9pQCS/zwjcQtcg+uT
2gbgRtMo+se1FV1YFylx0xIUWCh91uX1EAPhmw0IBQIDAQABo1MwUTAdBgNVHQ4E
FgQUuX7X9HO3KcD55BtDGgWleY18a3cwHwYDVR0jBBgwFoAUuX7X9HO3KcD55BtD
GgWleY18a3cwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAj/rZ
ga+ClC89q4a89U/OhX7hR8xOTPfpDLBGI8TpU2iXR57SZd4LvSNW1MTOJh/aTC/z
wA+MvhP3RK03kzW2pE3aauglT0bwx+mZ24oaQFGR1GLPhgq5BMina6Fr9C3NJggf
WtAoKNe+JoYUZkoLeBEnOcYEBZ1JYq7WBmctEY7sJgz456Coa0Ja+yXrPUPDbkKO
oTCeIwt9Fusk9T8y78+Ugx9eQuQGbwKF7evwQg0ZsuOWPvn0Y1qG0obph95tPp0s
HfNIDbTyjVga/gy3Et81E+AMrl7lKl5XZW0DZHSi41Y0KC5GhBBohrTIBoruIIkI
+hYCoquh8+xoYv32jg==
-----END CERTIFICATE-----

@ -1,129 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCfr4vk1jKqglCu
6yGwIkqNFY/khpYA4UzHMueQ3ChFNTuQo+NhKz6B4akmL7fAFvYyeXdAAceNsBJ+
eTDDB/DdLUqMPwYI1DUvG/8aDds7j+bRTX1ozLKML96qdL+JfGMAuT8jz37L66iW
DXYAS7dDHXOaNJ7HzUddngLMutjJ2NKi4jGhRHOeGxi22PLEL+yguZha3wyGMIks
2Gqz2rMqkuqLqAyEPX8GHWmNVXy0e/ruhp6VRa4vNyzWiMjs5Z6LR1/JQVzjlT5R
1MB1QYSp5u8tv6N+ySaH1kK/DiNi/TIAWnGGjaVkfW9iWANYodEuH/9yAzbFLT7e
vt92CRHVAgMBAAECggEBAJUZS/23IkeitcMdOK9E1Wc2Isy1/YmE1DOKjDzt04wL
UDqVS9GGly6ejVliZKeuyOIIGBhjkPfy1tHQRn9UAsoBaAHbNr83pRD/iwnAtlq+
2j3DpL0do/jRGY7+w3iT87zROuss6q9sslSo7O0JxWudLDtntnnIakI3L1YJgDG2
D92AVgwrDj+cePdns8CEOVjhW9qURxFz7dpC8AWS9mBmhcjCz2lAORjlpcR0TGEQ
+FN6KNVrsAi4ixURaetW1Jnj+N5v/rrmfDwGQq3rr5LL26rBao9ScteWJRUTlDqX
AkexjIrFeDKvlH6+rvwAq17dbTVvPmUjrmNd70AxgAECgYEA0hesj1BpELmxqowY
IIGKuIxVYAqBuZoU+rgiXPIjBvGX6iwvovUeGuDgeXPcb9bkmVvAfQM40JJyRVBm
Ww5tVX0+omrSrksOxf/+1g11Dybpnv4ZSa2cE30qQMxiyStADJHD+EyTZoRg3BUc
E7m77ml2/8EtrQ5lIG8aBDvrfdUCgYEAwpQtnshmzj9vQF2webxFCnUA5judEwpi
T8bwlJlPAB0l0K70lFkju3W8H52qHIoy+FR6kyoC76q5G4s8gVx5sPilOf7Gph29
w3IfSKsk3BC2xKl8saKZvMBmve02EtZVCf5JAoeD9KzfVOPculPljcKmEetI68qn
PPaaozVtRAECgYEAqzkoJdT/C+aLadergjKRgD6/BfsKJt3w4zVWrDGbYnlbujow
yLrEwlssF0/aBDw7KtGgW0JY94OjJeKUyPlFGjts5Kny8qGxdKViZ8mn8aVhGXc1
3NplLW0BFrZ8fD+Hf7b85ExkhVS2LCf4LgtdorzJgz9JnpTwzjI+Hd1H29ECgYEA
p3UDNg3efE4XntuCz6H6AR/lID/Z1NMw/NuHnTu7w6tSKiEIGMwGdoTC3KrCBkHh
z9pUi2aylDTnjg7siaBekrHK8PiVWc1qzVPgHJg95q7zvJjo2a/Ig6tKQNZvnRKc
qTcQ+n5KUD6fDd30zt75RmFory9A2LzV5R+OwjtuyAECgYBZrqUVGu61Rod3zFvz
y/SAirOMEgNDNfxGKSyuUwllrX/9H9jmmcM198Sx/bGXPX80H6f8Ov0Od46MhpXR
rnhHDQ6N/8OPzeZ5C7ri/ku1RS11Q7Z+a9kn5VS3gjFZpHCu2GIa6Tzn3Ag+czV1
3QpC2/6ydTgrrDAhNBwcZ5xY/g==
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIFAzCCA+ugAwIBAgIUBxLi0l/lss+0yOGpKQjfW+GTHI4wDQYJKoZIhvcNAQEL
BQAwgZYxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDU0ZPMQsw
CQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEaMBgGA1UEAwwRaW52YWxpZHBhcnRu
ZXIxY2ExNDAyBgkqhkiG9w0BCQEWJWludmFsaWRwYXJ0bmVyMWNhQGludmFsaWRw
YXJ0bmVyMS5jb20wIBcNMjEwNjA3MTcwNTUyWhgPMjEyMTA1MTQxNzA1NTJaMIGg
MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExDDAKBgNVBAcMA1NGTzELMAkGA1UE
CgwCTUMxDTALBgNVBAsMBHJvb3QxHzAdBgNVBAMMFmludmFsaWRwYXJ0bmVyMWNs
aWVudDExOTA3BgkqhkiG9w0BCQEWKmludmFsaWRwYXJ0bmVyMWNsaWVudDFAaW52
YWxpZHBhcnRuZXIxLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AJ+vi+TWMqqCUK7rIbAiSo0Vj+SGlgDhTMcy55DcKEU1O5Cj42ErPoHhqSYvt8AW
9jJ5d0ABx42wEn55MMMH8N0tSow/BgjUNS8b/xoN2zuP5tFNfWjMsowv3qp0v4l8
YwC5PyPPfsvrqJYNdgBLt0Mdc5o0nsfNR12eAsy62MnY0qLiMaFEc54bGLbY8sQv
7KC5mFrfDIYwiSzYarPasyqS6ouoDIQ9fwYdaY1VfLR7+u6GnpVFri83LNaIyOzl
notHX8lBXOOVPlHUwHVBhKnm7y2/o37JJofWQr8OI2L9MgBacYaNpWR9b2JYA1ih
0S4f/3IDNsUtPt6+33YJEdUCAwEAAaOCATkwggE1MBEGCWCGSAGG+EIBAQQEAwIG
wDAdBgNVHQ4EFgQUEUDbVrBFiwidyWrMY6rUqIi06bIwCQYDVR0TBAIwADAOBgNV
HQ8BAf8EBAMCBeAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMIHGBgNV
HSMEgb4wgbuAFCzA0qpygaQEk4vr+IKSqY1izLKnoYGMpIGJMIGGMQswCQYDVQQG
EwJVUzELMAkGA1UECAwCQ0ExDDAKBgNVBAcMA1NGTzELMAkGA1UECgwCTUMxDTAL
BgNVBAsMBHJvb3QxFzAVBgNVBAMMDmludmFsaWRpbnRlcmNhMScwJQYJKoZIhvcN
AQkBFhhpbnZhbGlkaW50ZXJjYUBhZG1pbi5jb22CFGmQswbSPaLG4R7azRkkC5XU
gkh5MA0GCSqGSIb3DQEBCwUAA4IBAQB5fiodcOYjxuCLjI+1AAsQP+mApMO5DJn3
tJh8ARt7TK1TzWBTaOQNe+MP4vUHKYu2pXDv07csgBM9F5WEXPbADTHOVd16h+5Q
OVK8JsfXaq26mg/+zp6UiK2JVHE+MCyVOfDhbpbu2WPXdzeOiPuQsBwzsolPWoMI
/dvIhKuHtUZ9wGSIurulCYPSqvUDOoHkFnIdsDMq3ISP5y6kCLCDDAqpwYb6PrfF
R0lJvbORWZ67LcHAvJgdmN1u93FG3yTh9xCl4fhCfNtsbVsQpXaYyTKhdBLaS9in
pyrOIxZJ9yiWk4iMv4/Ehm5BgR6CAJPHo3dvx46veSkVsztYQQDe
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEFDCCAvygAwIBAgIUaZCzBtI9osbhHtrNGSQLldSCSHkwDQYJKoZIhvcNAQEL
BQAwgYYxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDU0ZPMQsw
CQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEXMBUGA1UEAwwOaW52YWxpZGludGVy
Y2ExJzAlBgkqhkiG9w0BCQEWGGludmFsaWRpbnRlcmNhQGFkbWluLmNvbTAgFw0y
MTA2MDcxNzA1NTJaGA8yMTIxMDUxNDE3MDU1MlowgZYxCzAJBgNVBAYTAlVTMQsw
CQYDVQQIDAJDQTEMMAoGA1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwE
cm9vdDEaMBgGA1UEAwwRaW52YWxpZHBhcnRuZXIxY2ExNDAyBgkqhkiG9w0BCQEW
JWludmFsaWRwYXJ0bmVyMWNhQGludmFsaWRwYXJ0bmVyMS5jb20wggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDEMKBBPhzkvg+icZoRsN8CW2tlB4RZXo3C
apaQu2oJdEIqyKMRx86Uk7mRsW4rNWSbOjQwfCVsvhkUdriqBD+DfkzE03KKmhmL
hs2aC+ICb31aGyEvfWYFmKckY4zO8ptObaddWUZt27aie5vOzutB9n+oBmZMezd1
xc4dwOO+MzC92Ay3DIxw52SzGiywPGn3gfNWZ5NGvWM1poV4SwTi/eJXF/lwU9aY
Hl/+XOQ5/PJrIiQKGbBaywoOwYUU3FReosgCFVwDadnsj4ma++TKi/U7GQTcA01B
1F42sZx1vmLJC68jAyDJylAEtUZxiGs8LQ/S8B1zXBvdfiYW7RQfAgMBAAGjZjBk
MB0GA1UdDgQWBBQswNKqcoGkBJOL6/iCkqmNYsyypzAfBgNVHSMEGDAWgBRZVeo2
o+J44Ie43gS6L4tG3S0CaTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQE
AwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAUu60om2Fcx7h5C+bVmmBUhMDbnkWO9pa
lmEhmeuRrrmvSj/Ny6vmAmy9XOpox2PWMO5AndCIChLX697M4HskxIXCYhZzhjHE
x85WtmRjZAxdBA7vhgA6KIz58BJ6PmmJ3nYwc9dpyMthuMH74FcjfgsBL/1UalLI
26WtNMqEr+qK/drrlKpGHb1TjB3eWC1OPAwusgkw4uQBzKGHUZKxsVlaQ8jNkLdq
t31kMk770wXPh57N1tMn+gF21kACbkk0L4os+5AknYXWUS1A546I1TiEKmbKktPa
SdZIUT2AdIpZl4XMR5DZXBhMw8i/XyNfU6mW4b7TRt+QHU8l8ao47Q==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIECDCCAvCgAwIBAgIUK5+/p9u9ZYQuD9obuRHeJx0msBgwDQYJKoZIhvcNAQEL
BQAwgYoxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDU0ZPMQsw
CQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEcMBoGA1UEAwwTcm9vdGludmFsaWRj
YS5hZG1pbjEmMCQGCSqGSIb3DQEJARYXcm9vdGludmFsaWRjYUBhZG1pbi5jb20w
IBcNMjEwNjA3MTcwNTUyWhgPMjEyMTA1MTQxNzA1NTJaMIGGMQswCQYDVQQGEwJV
UzELMAkGA1UECAwCQ0ExDDAKBgNVBAcMA1NGTzELMAkGA1UECgwCTUMxDTALBgNV
BAsMBHJvb3QxFzAVBgNVBAMMDmludmFsaWRpbnRlcmNhMScwJQYJKoZIhvcNAQkB
FhhpbnZhbGlkaW50ZXJjYUBhZG1pbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQDNNU2p6MImjkrboq5MG7x422jISEYA9Zi/AMruUlQIXYwNUClc
yhalIPaToNRDBZ1mxj1uhdS/bxbAGxfO7EDQAcTGzIMhlkC+i/zLTSXTsoHjmgrt
5ZNQsc2Ok/a4aMpDUxZIx480Gm1GWEn5wrZpKJPdPnwwOg8tcjT4FCxI3CsMYQqb
UOR3iJn9IRyqTc1M/LCt5rYsd3slXVMnEOU5iu4UHJaNzKLlfsnB2LsdVqGqKA2e
nc6xdui+iJh81dqX/0RVUmyz4lDvhw8qfE58WAo4iIcpjBDcS8GPwt7WBF5KR120
HWF3HErVOsra/eVPK3iZU5vvWuU+zQ8pAm5DAgMBAAGjZjBkMB0GA1UdDgQWBBRZ
Veo2o+J44Ie43gS6L4tG3S0CaTAfBgNVHSMEGDAWgBS5ftf0c7cpwPnkG0MaBaV5
jXxrdzASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
9w0BAQsFAAOCAQEAjnY1t9Pt8DxhExpqnLBLkhGeg+upWQutTsvW+JMowPw+rX3H
m7mRKDkGl98Ol9m/6Iwx4kjgNz/bFx9flgJTYKvLE+yK/Jg4cizMjE4s9CzBA9ic
R20L0MrRS3w8ae6IXXDZaaZvwmUqxYOCChr1mXslP59EXPPeTbQa2asTAz5sYAFV
btPAjNa0T3KGcSbKyfZj3kAmNBFXrpyS0FcEQCt/u3USx1zGF1YuPGte0VBxtYw1
S/6DAeff+3rA9FAXXoG4qu+ZKu2kYydyJJPborTtJ3A/ATJmcJL2KW6ADHRK7rn1
NLj25w6mQoSRhoOLWHe+oWNF5nMO1SmMzfwlEQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID+TCCAuGgAwIBAgIUMcRYNxIDRzqdAgyjxeKuyrSVsscwDQYJKoZIhvcNAQEL
BQAwgYoxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDU0ZPMQsw
CQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEcMBoGA1UEAwwTcm9vdGludmFsaWRj
YS5hZG1pbjEmMCQGCSqGSIb3DQEJARYXcm9vdGludmFsaWRjYUBhZG1pbi5jb20w
IBcNMjEwNjA3MTcwNTUyWhgPMjEyMTA1MTQxNzA1NTJaMIGKMQswCQYDVQQGEwJV
UzELMAkGA1UECAwCQ0ExDDAKBgNVBAcMA1NGTzELMAkGA1UECgwCTUMxDTALBgNV
BAsMBHJvb3QxHDAaBgNVBAMME3Jvb3RpbnZhbGlkY2EuYWRtaW4xJjAkBgkqhkiG
9w0BCQEWF3Jvb3RpbnZhbGlkY2FAYWRtaW4uY29tMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAzmtt2EEdHNucUr8lZt8owINf9dSmCcpt663rnj833TO1
mCdKdmZvQYzgvdfVCLqonj5CaHts4GCyh3PeHxU+zqjEWxPbZCSkITKOtn3AblTJ
n4yFGpV6eIuGRFSL6TAaSPOyt59ZIFfSn5HDpVtET2/1hKRjjEnWhKy1pIG2J/mp
BaXO7QJtJyTbYdXm2AXorQChbX8T5J965wl4k/xLGrHtRcvaDeZsy9TdtYLseC78
bLFVwi7gAu3S9R6u9AuoVEn3rSZXaF+wSkH0GTX8rP049wQ9pQCS/zwjcQtcg+uT
2gbgRtMo+se1FV1YFylx0xIUWCh91uX1EAPhmw0IBQIDAQABo1MwUTAdBgNVHQ4E
FgQUuX7X9HO3KcD55BtDGgWleY18a3cwHwYDVR0jBBgwFoAUuX7X9HO3KcD55BtD
GgWleY18a3cwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAj/rZ
ga+ClC89q4a89U/OhX7hR8xOTPfpDLBGI8TpU2iXR57SZd4LvSNW1MTOJh/aTC/z
wA+MvhP3RK03kzW2pE3aauglT0bwx+mZ24oaQFGR1GLPhgq5BMina6Fr9C3NJggf
WtAoKNe+JoYUZkoLeBEnOcYEBZ1JYq7WBmctEY7sJgz456Coa0Ja+yXrPUPDbkKO
oTCeIwt9Fusk9T8y78+Ugx9eQuQGbwKF7evwQg0ZsuOWPvn0Y1qG0obph95tPp0s
HfNIDbTyjVga/gy3Et81E+AMrl7lKl5XZW0DZHSi41Y0KC5GhBBohrTIBoruIIkI
+hYCoquh8+xoYv32jg==
-----END CERTIFICATE-----

@ -1,27 +0,0 @@
-----BEGIN X509 CRL-----
MIICBDCB7QIBATANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCVVMxCzAJBgNV
BAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJBgNVBAoMAk1DMQ0wCwYDVQQLDARyb290
MRMwEQYDVQQDDApwYXJ0bmVyMWNhMSYwJAYJKoZIhvcNAQkBFhdwYXJ0bmVyMWNh
QHBhcnRuZXIxLmNvbRcNMjEwNjA3MTcwNjAwWhcNMjIwNjA3MTcwNjAwWjAnMCUC
FGltgEkvXupxY562dERH8+uKOf89Fw0yMTA2MDcxNzA2MDBaoA4wDDAKBgNVHRQE
AwIBADANBgkqhkiG9w0BAQsFAAOCAQEABF/7Kq+byYi/bRoftL8xqgSGcaLVuCOF
BZVZXDKjyYfISwBqbvPSqtIvnFO1ewicgD7dNIZwWcQ9Kx7OOz4BA6Pe8YPtiBfp
HZMabT8BS2eLePvViGumY7PTo3oIk3yXylOtzMDo59WQhCH/0vp5xjzJC+VFex/W
p/an5ii1y3Q1FpEZNer6jpU0xJEJ2mCaGT/zuj6Mg1awWqmmYce3BahZeCNj8Wyx
GIy8bGUjOdJyp99rAF9euCZ45pAjI12sg9lhPIVkp3Wnoy3La4Yj219Elc3MbJvF
8GEFEmZ0Lm5Ze/EG5VyLB+wRpggeSJTc20i/eGWdaWg8AEukCgMdCg==
-----END X509 CRL-----
-----BEGIN X509 CRL-----
MIICLDCCARQCAQEwDQYJKoZIhvcNAQELBQAwgYExCzAJBgNVBAYTAlVTMQswCQYD
VQQIDAJDQTEMMAoGA1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9v
dDETMBEGA1UEAwwKcGFydG5lcjJjYTEmMCQGCSqGSIb3DQEJARYXcGFydG5lcjJj
YUBwYXJ0bmVyMi5jb20XDTIxMDYwNzE3MDYwMFoXDTIyMDYwNzE3MDYwMFowTjAl
AhRpbYBJL17qcWOetnRER/Prijn/PRcNMjEwNjA3MTcwNjAwWjAlAhR+2Aa1zeVQ
jbXFGnXFu53h4vZEahcNMjEwNjA3MTcwNjAwWqAOMAwwCgYDVR0UBAMCAQEwDQYJ
KoZIhvcNAQELBQADggEBAFXQOMk+6FDP8bm9TGK079IHojhooipo+9x3I1y/kUhH
XY7xuyTXOvzv14//xenDuryIjSAC8pyqbls+DcUXkmGZ/nIWugtMykGLNgqqo/Oe
pfoUSXRJP7CtvfHa4ejfr3q1t5MXfM3nqBQumu65slWjDFtE6mZF4ANcsIlsNQ10
GTkDIdDHgUWxmZlBzTkoofvYspixuUptpJfl5eei9SDA+T1uADKnjARkxVv8xeYi
QwTp6jVYq6YKc9z0l1UMadnFQz8osk7QNypWnsrD0+iBB1if8ikJwy+8BWayTkgQ
tWLFT4n/c1m/wYzSclvZUUOxkkkE4Q9fZ3ReCADC+bQ=
-----END X509 CRL-----

@ -1,70 +0,0 @@
-----BEGIN CERTIFICATE-----
MIID8DCCAtigAwIBAgIUNniG6StciHezbAqX+uNMciPW7jowDQYJKoZIhvcNAQEL
BQAweDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJ
BgNVBAoMAk1DMQ0wCwYDVQQLDARyb290MRAwDgYDVQQDDAdpbnRlcmNhMSAwHgYJ
KoZIhvcNAQkBFhFpbnRlcmNhQGFkbWluLmNvbTAgFw0yMTA2MDcxNzA1NDdaGA8y
MTIxMDUxNDE3MDU0N1owgYExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoG
A1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDETMBEGA1UEAwwK
cGFydG5lcjFjYTEmMCQGCSqGSIb3DQEJARYXcGFydG5lcjFjYUBwYXJ0bmVyMS5j
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDR8KbDV1MbtC1Siuo2
pbOU6eMRaNyDdlhcz48FY+mKGsUEAePceFJTvh1w9gXwt/A26CO02BVdTPYowudf
Qkl9v+qSRIKXgKz1fkNUW4xYKl7KsgABi/zpgY/bM3CarBcBan9VKWapgx680Aj2
bv99ODNqZTH9Iwdq2IrHNBplLp2TmFao7oKz+LeMV6ZrdfY1THf1AuprD86Ccxfa
9YAyuMI4t7BKqmIqMuDKSSykXuEDY/CCDWw8o/0rg6baoM4bKzipv/4oqaegM3MB
8vt979rx4PGH69+/JSMt7wL3SQbkQtMNODZyGM/HW+TsPAFYfHPsURVRezFpOB7G
OoTdAgMBAAGjZjBkMB0GA1UdDgQWBBSB8CJNxPXuu/mEDmD1+rPhI/qN5DAfBgNV
HSMEGDAWgBT8BlnPk8BS8+JHlIEoCp3sO8jDDjASBgNVHRMBAf8ECDAGAQH/AgEA
MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAKb5S3NTSxSJrI5Mk
EKoULvy7vKh+W/o5wDKm8ILwJHn76HFyq3Nl0zYdoshROnLG8gL69rMWZgTg+Fsl
teX8pNvLEQV7Asx5Yvn2oFBQqRevwGsg2z48et5SIq5pDYeThwUMbdrGuhkEkizW
ecBUN8j7auRLSpx5ornl9zFx5bvsVb4Dy/rIMVnPiw3VniOAOplGIJOm/TiPxTR0
qyzdHljsRbM0uyw81QkeskuJWCpmKTFZxfV1Jww3ScKApNY8WFW+iuarWBvRTq7l
3AxXcE11ms92rnZw3vFvrIfM6WlE7Idb0rlRK69e73j40eBtJN5i6L7IPJ7Uht+N
mLfQvw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID6jCCAtKgAwIBAgIUTwPfI+2FxYq0V6uukemLf67qANowDQYJKoZIhvcNAQEL
BQAwfDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJ
BgNVBAoMAk1DMQ0wCwYDVQQLDARyb290MRUwEwYDVQQDDAxyb290Y2EuYWRtaW4x
HzAdBgkqhkiG9w0BCQEWEHJvb3RjYUBhZG1pbi5jb20wIBcNMjEwNjA3MTcwNTQ3
WhgPMjEyMTA1MTQxNzA1NDdaMHgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEM
MAoGA1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEQMA4GA1UE
AwwHaW50ZXJjYTEgMB4GCSqGSIb3DQEJARYRaW50ZXJjYUBhZG1pbi5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxuUWq2F6MFQLeFVBB800pjiJv
pqrpMb8lv5aEOX87slRRkIVe0M/6mSlNvJSSclGindIhsWxaYD4Kend+o+ODhMqT
Jl7zvVTTluGg8SK22kyJ8DTWHnhnFhpoKVLc5qjgvglOf0h7S9F/tL5AkpGoBq7t
PkbOJPxKR7bvn34Iux3HgS1uzwZqHSYBcNHuYB6PSgyQJiNLIrA/019YqqUI5R+W
V/Nb/kkrnsUS+hU6ntAtewus0irO+4fJzBlpN+bvbEBdVHeVmIYhF6ILxtCGWX5l
lOlDrYNXiff0ksKtEvyUV/NFOASixEBMQ88Un7NGHR8y1NW3fCGiVkOhvaprAgMB
AAGjZjBkMB0GA1UdDgQWBBT8BlnPk8BS8+JHlIEoCp3sO8jDDjAfBgNVHSMEGDAW
gBTj0UDC6u67VvpJ2NmXE7vz77nHHTASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1Ud
DwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAZYQg0VUOQ1DGoU0y0TsTzAZ4
IEy5xavV7Nma9AJI0ZVFpqGEBjTXjxi7r/co1EREN3bi7QnZfJhU4SGVZ0T7wq+p
/S3x16DEPEufa3JmP+brBPOOP/5EJX5+2BXMUWuDcY7MAokaAIAudjmVk32FoZgy
54FkZ+YRillU++7k0ie8EEYE8pN2ABIqNCdHxGEhwEc0wVwB6bBONmcEssYmipUh
DQH6+sfKBcd+sUMGG3qd79sE7BF9w8bAHhKcBm5eTdEks9jh6H1o0PgBvFP8fFzF
q89KGuLw7T0n/Khkmrv5cifwmTpg42Ivorv8qk02aeiOAGiMyFFJ38BQtH64LQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID2zCCAsOgAwIBAgIURc832yfuirkVrhWhC4O1uBfTZXAwDQYJKoZIhvcNAQEL
BQAwfDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJ
BgNVBAoMAk1DMQ0wCwYDVQQLDARyb290MRUwEwYDVQQDDAxyb290Y2EuYWRtaW4x
HzAdBgkqhkiG9w0BCQEWEHJvb3RjYUBhZG1pbi5jb20wIBcNMjEwNjA3MTcwNTQ3
WhgPMjEyMTA1MTQxNzA1NDdaMHwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEM
MAoGA1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEVMBMGA1UE
AwwMcm9vdGNhLmFkbWluMR8wHQYJKoZIhvcNAQkBFhByb290Y2FAYWRtaW4uY29t
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzKd0JrZR3N0A3C7Gp7sT
zLurt0pVjAIBh3N+5NsyY7eAHJWA7wRR+JpG4q6MxmYVWsk4MjsnWB0ViCCm+fTY
a9tFms6lmsjM4fJgIs8/DP+zBEOien7sD3kfddmI4ClODynNv3ODbJKyhzKQEOZ8
sdf61yWYuFzayEfNoon6BlqroPv9B0eAsgOFDndPo6vbqAFlrYAyVXx+7hmH7Hv6
8RWDaSr0uI62uhvAQeK4a+p9aTSwLcHRh1/7NezW9rzI0/7yzP3w/RS7tevDuacU
XMr3sH5xEUahGF72qYUVejUlP48fPLrdGK76QZk0M8K2EOyvuNq66P+UMialx+83
NwIDAQABo1MwUTAdBgNVHQ4EFgQU49FAwuruu1b6SdjZlxO78++5xx0wHwYDVR0j
BBgwFoAU49FAwuruu1b6SdjZlxO78++5xx0wDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAQEADfrsmYBaeV4/MTRVazsey/o0ZhBoLJ+3RFYC6+M2lYB1
yT92tbAT3787aHTw/SdFvA11oT+lMDEmBWowzZ1bp/J7tqlqMcmwL4QyhZjp0gmK
eqDXy2Jui/fOTRzWQ1ka7mR6OTWxxVoIjKVvJ/AysqGCTFMXZXrMthtCuQDG+b85
B3ALz6/j0ZFqgKzftCIuY0UnBtDEuKkAa0QkDMHLvcMAw7V/etpQPypCXqmwnc2e
vvL6cSvakEVE7rErhIeeL+1m2TBSWNrPVIvggLMv655meqkhGQn9uYyiGw6i/2V/
ngBAs4gYDvk20Cyg0kxQONmzreAdFzArud+k7FofZw==
-----END CERTIFICATE-----

@ -1,126 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8YRSLAPea6rIG
tgDxF+q4KVlm5zV5VWyvKf6KjECZC6fHekQkP1sFYhG6+wq+nDT8hf+Em8JYa/oV
WMi4QDHZkzryJC2rEyukq1Pi9ELBhGfbLw356zP4zCK+/RtiR06B/UOPkQ8/Itz+
fTbuU7LrgIA6AT8rDG5kTOuKBvcNWDx02QEeAguZVXSVOG1A6Un8NsL/pFi9tsUU
qW9jgTA389wHunggAKa+KDPg5HXsqZfG/sioJv3iZw42zvmBaSaQJ+ZtQeVx2zu+
OUMWhke5nmr+6ohLqG0R8GwKhW6AxlErKvFZXEKhLTobUAWOExL6ImtqgvYUc8wT
gvN92pfPAgMBAAECggEBAJ0HN76fcccbOIdLlAFk9G3LWhDjTrnzsYNaOCp5uydY
heVMUBz/Cvqzwx/gQBaf07NkZ5i81gYrC+5bcgXUzTkW95389mySsGC1yFl5T2RM
4N3enYHkxA/y6kvWZMtJsXG+EmFMhC8W+qzQ58dG0fBpz3mKrINP+310eSs3nxzp
MGnAHaawB8KVTIfqsFbVbT+DMShU8KkZSe8HAwEZF0vsD0Epq/IftH3H+gucH8Ny
5O3/hfvU4CBn0RxJyH239YDyPaf+TeZfJwI361k5se/aDwicj2azFo60uObsV8FT
DhYxPFB39LT0kKgeo14SrW6USyhv6PEZs/x6dTKyw8ECgYEA3drXVsEwOuVrg8DD
H8/pfsKS6EXB9Enxs5jzeS2nWR6qjjEo9+Ks4dZTRstlkCe+WSMgeeX9snDCJodJ
cG/5XDpg5GlrcapRz79zJ7SKcaiaH/EKs7pmcUR+3BanGYB2AWYjwil9yLTv7FB9
o08Xx6dEbm/doQlOoTNrmZUcKH8CgYEA2V9JnkJmqVZAyYISRniESZNxHElVd98B
jR546VeGS41faEyiXZd6vrjubbMkxylsNBxri774g04ki+T3fNSXNDBr1TcOf4do
XoVhrVk03p2xTt/4tDV5XfefIam11POEVs/H9R5cUeF5aylOP5Wi3tNveSDeqhwW
RSKfOHuRaLECgYAc46Bi5ak4IiPL9k/yVoqbPQ8QO/UzsGVO873Qq8c87adb+L7S
+Kt2hQg3EclZ6jL5PH/AH9jXYaOGjNtdTtdz0Q5I8AlTtdANc2q1YuccQc5AFo1E
NiOc4ER8uF5uDbJQIFLLt8dvWVBcv2Z825HHJ9rbXqnHjIS2rRF34FjYVQKBgGUz
p+K2p3VPYvpuRHPqyCw5KQAyZEha2y4IceKxjSS/vRuiEjXgwJTrJJaOQSE4d9gL
I0b8slbvmrRG9bJ4h60Unh+2clmNgVoAX2mFjsfWQyalv/SmsMq+7qeNi8qJVaPV
ORM1/2VfxFfP805HLHzxk4SheQlZ6kRlyhtR7HEBAoGAMPaMPm0PaPesN6dpwgKD
HHm4BgniKafmikjkieuVQgtu/Rl/1Eq+haGHIDMQtRn9fD88y1lETEw4o2vXUDjI
vBFkGE+Mf/Vjg6V1THAGd9XseLgAK2PCvfEDsCYAiyEEVY0hPfmgQwNZxxCt94fE
fjI21dc+cX9CHXTHyzORnWE=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIEyDCCA7CgAwIBAgIUaW2ASS9e6nFjnrZ0REfz64o5/zwwDQYJKoZIhvcNAQEL
BQAwgYExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDU0ZPMQsw
CQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDETMBEGA1UEAwwKcGFydG5lcjFjYTEm
MCQGCSqGSIb3DQEJARYXcGFydG5lcjFjYUBwYXJ0bmVyMS5jb20wIBcNMjEwNjA3
MTcwNTQ3WhgPMjEyMTA1MTQxNzA1NDdaMIGLMQswCQYDVQQGEwJVUzELMAkGA1UE
CAwCQ0ExDDAKBgNVBAcMA1NGTzELMAkGA1UECgwCTUMxDTALBgNVBAsMBHJvb3Qx
GDAWBgNVBAMMD3BhcnRuZXIxY2xpZW50MTErMCkGCSqGSIb3DQEJARYccGFydG5l
cjFjbGllbnQxQHBhcnRuZXIxLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBALxhFIsA95rqsga2APEX6rgpWWbnNXlVbK8p/oqMQJkLp8d6RCQ/WwVi
Ebr7Cr6cNPyF/4Sbwlhr+hVYyLhAMdmTOvIkLasTK6SrU+L0QsGEZ9svDfnrM/jM
Ir79G2JHToH9Q4+RDz8i3P59Nu5TsuuAgDoBPysMbmRM64oG9w1YPHTZAR4CC5lV
dJU4bUDpSfw2wv+kWL22xRSpb2OBMDfz3Ae6eCAApr4oM+Dkdeypl8b+yKgm/eJn
DjbO+YFpJpAn5m1B5XHbO745QxaGR7meav7qiEuobRHwbAqFboDGUSsq8VlcQqEt
OhtQBY4TEvoia2qC9hRzzBOC833al88CAwEAAaOCASgwggEkMBEGCWCGSAGG+EIB
AQQEAwIGwDAdBgNVHQ4EFgQUteJ5GVlEpzaoonh4YXoc+1103lowCQYDVR0TBAIw
ADAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MIG1BgNVHSMEga0wgaqAFIHwIk3E9e67+YQOYPX6s+Ej+o3koXykejB4MQswCQYD
VQQGEwJVUzELMAkGA1UECAwCQ0ExDDAKBgNVBAcMA1NGTzELMAkGA1UECgwCTUMx
DTALBgNVBAsMBHJvb3QxEDAOBgNVBAMMB2ludGVyY2ExIDAeBgkqhkiG9w0BCQEW
EWludGVyY2FAYWRtaW4uY29tghQ2eIbpK1yId7NsCpf640xyI9buOjANBgkqhkiG
9w0BAQsFAAOCAQEABiqi7zOT55MIm5rbCGwe00LvAghbkfUitDEEotRjvF8E/fvA
rwnbqgBDbetYtI+88ml3NhdU2B3qZA8Z/KXnjJA+vmNmpdRVYGnl8BdKjqTUl+QV
d1vm0IbOID33gOKhaxba+Tbq7WYnzCMltqOzqtjgCUmJamacGR5sDYvz057vWEM/
19Gw1agAAY+sb1Vx7BwM6A81iKP7rf1z0jKZTVMc8bW1IOZJxqDsMosnuSAyQwMK
4Bwt6CEbWjknRZ/jTioM0C2HFpWXz51SyNwP583s60OVqf7/NYb1LC3lWrpWL7yf
rsHBob8jsrkCRHbRHIjXjio3l29ObL5AfQm3Ig==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID8DCCAtigAwIBAgIUNniG6StciHezbAqX+uNMciPW7jowDQYJKoZIhvcNAQEL
BQAweDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJ
BgNVBAoMAk1DMQ0wCwYDVQQLDARyb290MRAwDgYDVQQDDAdpbnRlcmNhMSAwHgYJ
KoZIhvcNAQkBFhFpbnRlcmNhQGFkbWluLmNvbTAgFw0yMTA2MDcxNzA1NDdaGA8y
MTIxMDUxNDE3MDU0N1owgYExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoG
A1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDETMBEGA1UEAwwK
cGFydG5lcjFjYTEmMCQGCSqGSIb3DQEJARYXcGFydG5lcjFjYUBwYXJ0bmVyMS5j
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDR8KbDV1MbtC1Siuo2
pbOU6eMRaNyDdlhcz48FY+mKGsUEAePceFJTvh1w9gXwt/A26CO02BVdTPYowudf
Qkl9v+qSRIKXgKz1fkNUW4xYKl7KsgABi/zpgY/bM3CarBcBan9VKWapgx680Aj2
bv99ODNqZTH9Iwdq2IrHNBplLp2TmFao7oKz+LeMV6ZrdfY1THf1AuprD86Ccxfa
9YAyuMI4t7BKqmIqMuDKSSykXuEDY/CCDWw8o/0rg6baoM4bKzipv/4oqaegM3MB
8vt979rx4PGH69+/JSMt7wL3SQbkQtMNODZyGM/HW+TsPAFYfHPsURVRezFpOB7G
OoTdAgMBAAGjZjBkMB0GA1UdDgQWBBSB8CJNxPXuu/mEDmD1+rPhI/qN5DAfBgNV
HSMEGDAWgBT8BlnPk8BS8+JHlIEoCp3sO8jDDjASBgNVHRMBAf8ECDAGAQH/AgEA
MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAKb5S3NTSxSJrI5Mk
EKoULvy7vKh+W/o5wDKm8ILwJHn76HFyq3Nl0zYdoshROnLG8gL69rMWZgTg+Fsl
teX8pNvLEQV7Asx5Yvn2oFBQqRevwGsg2z48et5SIq5pDYeThwUMbdrGuhkEkizW
ecBUN8j7auRLSpx5ornl9zFx5bvsVb4Dy/rIMVnPiw3VniOAOplGIJOm/TiPxTR0
qyzdHljsRbM0uyw81QkeskuJWCpmKTFZxfV1Jww3ScKApNY8WFW+iuarWBvRTq7l
3AxXcE11ms92rnZw3vFvrIfM6WlE7Idb0rlRK69e73j40eBtJN5i6L7IPJ7Uht+N
mLfQvw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID6jCCAtKgAwIBAgIUTwPfI+2FxYq0V6uukemLf67qANowDQYJKoZIhvcNAQEL
BQAwfDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJ
BgNVBAoMAk1DMQ0wCwYDVQQLDARyb290MRUwEwYDVQQDDAxyb290Y2EuYWRtaW4x
HzAdBgkqhkiG9w0BCQEWEHJvb3RjYUBhZG1pbi5jb20wIBcNMjEwNjA3MTcwNTQ3
WhgPMjEyMTA1MTQxNzA1NDdaMHgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEM
MAoGA1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEQMA4GA1UE
AwwHaW50ZXJjYTEgMB4GCSqGSIb3DQEJARYRaW50ZXJjYUBhZG1pbi5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxuUWq2F6MFQLeFVBB800pjiJv
pqrpMb8lv5aEOX87slRRkIVe0M/6mSlNvJSSclGindIhsWxaYD4Kend+o+ODhMqT
Jl7zvVTTluGg8SK22kyJ8DTWHnhnFhpoKVLc5qjgvglOf0h7S9F/tL5AkpGoBq7t
PkbOJPxKR7bvn34Iux3HgS1uzwZqHSYBcNHuYB6PSgyQJiNLIrA/019YqqUI5R+W
V/Nb/kkrnsUS+hU6ntAtewus0irO+4fJzBlpN+bvbEBdVHeVmIYhF6ILxtCGWX5l
lOlDrYNXiff0ksKtEvyUV/NFOASixEBMQ88Un7NGHR8y1NW3fCGiVkOhvaprAgMB
AAGjZjBkMB0GA1UdDgQWBBT8BlnPk8BS8+JHlIEoCp3sO8jDDjAfBgNVHSMEGDAW
gBTj0UDC6u67VvpJ2NmXE7vz77nHHTASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1Ud
DwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAZYQg0VUOQ1DGoU0y0TsTzAZ4
IEy5xavV7Nma9AJI0ZVFpqGEBjTXjxi7r/co1EREN3bi7QnZfJhU4SGVZ0T7wq+p
/S3x16DEPEufa3JmP+brBPOOP/5EJX5+2BXMUWuDcY7MAokaAIAudjmVk32FoZgy
54FkZ+YRillU++7k0ie8EEYE8pN2ABIqNCdHxGEhwEc0wVwB6bBONmcEssYmipUh
DQH6+sfKBcd+sUMGG3qd79sE7BF9w8bAHhKcBm5eTdEks9jh6H1o0PgBvFP8fFzF
q89KGuLw7T0n/Khkmrv5cifwmTpg42Ivorv8qk02aeiOAGiMyFFJ38BQtH64LQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID2zCCAsOgAwIBAgIURc832yfuirkVrhWhC4O1uBfTZXAwDQYJKoZIhvcNAQEL
BQAwfDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJ
BgNVBAoMAk1DMQ0wCwYDVQQLDARyb290MRUwEwYDVQQDDAxyb290Y2EuYWRtaW4x
HzAdBgkqhkiG9w0BCQEWEHJvb3RjYUBhZG1pbi5jb20wIBcNMjEwNjA3MTcwNTQ3
WhgPMjEyMTA1MTQxNzA1NDdaMHwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEM
MAoGA1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEVMBMGA1UE
AwwMcm9vdGNhLmFkbWluMR8wHQYJKoZIhvcNAQkBFhByb290Y2FAYWRtaW4uY29t
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzKd0JrZR3N0A3C7Gp7sT
zLurt0pVjAIBh3N+5NsyY7eAHJWA7wRR+JpG4q6MxmYVWsk4MjsnWB0ViCCm+fTY
a9tFms6lmsjM4fJgIs8/DP+zBEOien7sD3kfddmI4ClODynNv3ODbJKyhzKQEOZ8
sdf61yWYuFzayEfNoon6BlqroPv9B0eAsgOFDndPo6vbqAFlrYAyVXx+7hmH7Hv6
8RWDaSr0uI62uhvAQeK4a+p9aTSwLcHRh1/7NezW9rzI0/7yzP3w/RS7tevDuacU
XMr3sH5xEUahGF72qYUVejUlP48fPLrdGK76QZk0M8K2EOyvuNq66P+UMialx+83
NwIDAQABo1MwUTAdBgNVHQ4EFgQU49FAwuruu1b6SdjZlxO78++5xx0wHwYDVR0j
BBgwFoAU49FAwuruu1b6SdjZlxO78++5xx0wDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAQEADfrsmYBaeV4/MTRVazsey/o0ZhBoLJ+3RFYC6+M2lYB1
yT92tbAT3787aHTw/SdFvA11oT+lMDEmBWowzZ1bp/J7tqlqMcmwL4QyhZjp0gmK
eqDXy2Jui/fOTRzWQ1ka7mR6OTWxxVoIjKVvJ/AysqGCTFMXZXrMthtCuQDG+b85
B3ALz6/j0ZFqgKzftCIuY0UnBtDEuKkAa0QkDMHLvcMAw7V/etpQPypCXqmwnc2e
vvL6cSvakEVE7rErhIeeL+1m2TBSWNrPVIvggLMv655meqkhGQn9uYyiGw6i/2V/
ngBAs4gYDvk20Cyg0kxQONmzreAdFzArud+k7FofZw==
-----END CERTIFICATE-----

@ -1,27 +0,0 @@
-----BEGIN X509 CRL-----
MIICBDCB7QIBATANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCVVMxCzAJBgNV
BAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJBgNVBAoMAk1DMQ0wCwYDVQQLDARyb290
MRMwEQYDVQQDDApwYXJ0bmVyMWNhMSYwJAYJKoZIhvcNAQkBFhdwYXJ0bmVyMWNh
QHBhcnRuZXIxLmNvbRcNMjEwNjA3MTcwNjAwWhcNMjIwNjA3MTcwNjAwWjAnMCUC
FGltgEkvXupxY562dERH8+uKOf89Fw0yMTA2MDcxNzA2MDBaoA4wDDAKBgNVHRQE
AwIBADANBgkqhkiG9w0BAQsFAAOCAQEABF/7Kq+byYi/bRoftL8xqgSGcaLVuCOF
BZVZXDKjyYfISwBqbvPSqtIvnFO1ewicgD7dNIZwWcQ9Kx7OOz4BA6Pe8YPtiBfp
HZMabT8BS2eLePvViGumY7PTo3oIk3yXylOtzMDo59WQhCH/0vp5xjzJC+VFex/W
p/an5ii1y3Q1FpEZNer6jpU0xJEJ2mCaGT/zuj6Mg1awWqmmYce3BahZeCNj8Wyx
GIy8bGUjOdJyp99rAF9euCZ45pAjI12sg9lhPIVkp3Wnoy3La4Yj219Elc3MbJvF
8GEFEmZ0Lm5Ze/EG5VyLB+wRpggeSJTc20i/eGWdaWg8AEukCgMdCg==
-----END X509 CRL-----
-----BEGIN X509 CRL-----
MIICLDCCARQCAQEwDQYJKoZIhvcNAQELBQAwgYExCzAJBgNVBAYTAlVTMQswCQYD
VQQIDAJDQTEMMAoGA1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9v
dDETMBEGA1UEAwwKcGFydG5lcjJjYTEmMCQGCSqGSIb3DQEJARYXcGFydG5lcjJj
YUBwYXJ0bmVyMi5jb20XDTIxMDYwNzE3MDYwMFoXDTIyMDYwNzE3MDYwMFowTjAl
AhRpbYBJL17qcWOetnRER/Prijn/PRcNMjEwNjA3MTcwNjAwWjAlAhR+2Aa1zeVQ
jbXFGnXFu53h4vZEahcNMjEwNjA3MTcwNjAwWqAOMAwwCgYDVR0UBAMCAQEwDQYJ
KoZIhvcNAQELBQADggEBAFXQOMk+6FDP8bm9TGK079IHojhooipo+9x3I1y/kUhH
XY7xuyTXOvzv14//xenDuryIjSAC8pyqbls+DcUXkmGZ/nIWugtMykGLNgqqo/Oe
pfoUSXRJP7CtvfHa4ejfr3q1t5MXfM3nqBQumu65slWjDFtE6mZF4ANcsIlsNQ10
GTkDIdDHgUWxmZlBzTkoofvYspixuUptpJfl5eei9SDA+T1uADKnjARkxVv8xeYi
QwTp6jVYq6YKc9z0l1UMadnFQz8osk7QNypWnsrD0+iBB1if8ikJwy+8BWayTkgQ
tWLFT4n/c1m/wYzSclvZUUOxkkkE4Q9fZ3ReCADC+bQ=
-----END X509 CRL-----

@ -1,6 +0,0 @@
name = NSScrypto-partner2client1
nssSecmodDirectory = ./src/test/resources/keystore/partner2client1/nssdb
nssDbMode = readOnly
nssModule = keystore

@ -1,70 +0,0 @@
-----BEGIN CERTIFICATE-----
MIID8DCCAtigAwIBAgIUNniG6StciHezbAqX+uNMciPW7jswDQYJKoZIhvcNAQEL
BQAweDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJ
BgNVBAoMAk1DMQ0wCwYDVQQLDARyb290MRAwDgYDVQQDDAdpbnRlcmNhMSAwHgYJ
KoZIhvcNAQkBFhFpbnRlcmNhQGFkbWluLmNvbTAgFw0yMTA2MDcxNzA1NDlaGA8y
MTIxMDUxNDE3MDU0OVowgYExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoG
A1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDETMBEGA1UEAwwK
cGFydG5lcjJjYTEmMCQGCSqGSIb3DQEJARYXcGFydG5lcjJjYUBwYXJ0bmVyMi5j
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLvHvIuFFYmNYEA6P2
/RB3LBDpxbnjl7SU4KCWcfBxQ1guw3aG/HzjenKt3m6UmmESFSh0k4/a/s9m4z/M
ubVqrm0ll2HvyodetFL40jLgSCIbP3taCIhLptaOCB2P6keYEfjGdb5YTNMgCqYk
NYA+dgXtw1VMJvI7aRpmVOIPtQx/nqncigYzxykGlTbeusSPAGp7CAmxTZSJUFLI
ig0ReaKSopiQE2j/ljJXFK26sMlkq3Lw41E4fPju+PBeubeb6eT8fzhn0IaCgTeO
cZgKzVUv3MsrrKfDHXUhGAspKBGDkqkrogZ6UYcvyCLfnRM0vVGc1L7oaFnMMZ1m
NYRpAgMBAAGjZjBkMB0GA1UdDgQWBBSsXIVGVfgo124o7djQsYtrkYPWYzAfBgNV
HSMEGDAWgBT8BlnPk8BS8+JHlIEoCp3sO8jDDjASBgNVHRMBAf8ECDAGAQH/AgEA
MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABSHI1SgQ1FBWmPRZ
nXDspyvbvPsjk/p6erUVGGuDyy/F2rJldz7musNCL5ijAmlQfYPNMNoLU1BR+fAl
WSYfdjL1mMygXtj/KlaNqM5hQMUfyYa4Yk1ODaScl+wfIsSmzTSl/j4fMf58GYpr
9rssVveQrFAipeWhxgGqQNJooAbqmZKE4tePhKzrsH+B2hDEUnFptkasnQEkQQEZ
rSzJlU72U8p3Gwq9t9rKYoBLSr0yoBbh4fdFcPsuN/mZS6TNEu1Uc4ui9eWheGTM
RCNGehiXAczfIhf9WfMfyNhp5/pZc2nTeV/LsSjuCFXUdoL5rAESPcHBc56vXtcV
1ywC0A==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID6jCCAtKgAwIBAgIUTwPfI+2FxYq0V6uukemLf67qANowDQYJKoZIhvcNAQEL
BQAwfDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJ
BgNVBAoMAk1DMQ0wCwYDVQQLDARyb290MRUwEwYDVQQDDAxyb290Y2EuYWRtaW4x
HzAdBgkqhkiG9w0BCQEWEHJvb3RjYUBhZG1pbi5jb20wIBcNMjEwNjA3MTcwNTQ3
WhgPMjEyMTA1MTQxNzA1NDdaMHgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEM
MAoGA1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEQMA4GA1UE
AwwHaW50ZXJjYTEgMB4GCSqGSIb3DQEJARYRaW50ZXJjYUBhZG1pbi5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxuUWq2F6MFQLeFVBB800pjiJv
pqrpMb8lv5aEOX87slRRkIVe0M/6mSlNvJSSclGindIhsWxaYD4Kend+o+ODhMqT
Jl7zvVTTluGg8SK22kyJ8DTWHnhnFhpoKVLc5qjgvglOf0h7S9F/tL5AkpGoBq7t
PkbOJPxKR7bvn34Iux3HgS1uzwZqHSYBcNHuYB6PSgyQJiNLIrA/019YqqUI5R+W
V/Nb/kkrnsUS+hU6ntAtewus0irO+4fJzBlpN+bvbEBdVHeVmIYhF6ILxtCGWX5l
lOlDrYNXiff0ksKtEvyUV/NFOASixEBMQ88Un7NGHR8y1NW3fCGiVkOhvaprAgMB
AAGjZjBkMB0GA1UdDgQWBBT8BlnPk8BS8+JHlIEoCp3sO8jDDjAfBgNVHSMEGDAW
gBTj0UDC6u67VvpJ2NmXE7vz77nHHTASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1Ud
DwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAZYQg0VUOQ1DGoU0y0TsTzAZ4
IEy5xavV7Nma9AJI0ZVFpqGEBjTXjxi7r/co1EREN3bi7QnZfJhU4SGVZ0T7wq+p
/S3x16DEPEufa3JmP+brBPOOP/5EJX5+2BXMUWuDcY7MAokaAIAudjmVk32FoZgy
54FkZ+YRillU++7k0ie8EEYE8pN2ABIqNCdHxGEhwEc0wVwB6bBONmcEssYmipUh
DQH6+sfKBcd+sUMGG3qd79sE7BF9w8bAHhKcBm5eTdEks9jh6H1o0PgBvFP8fFzF
q89KGuLw7T0n/Khkmrv5cifwmTpg42Ivorv8qk02aeiOAGiMyFFJ38BQtH64LQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID2zCCAsOgAwIBAgIURc832yfuirkVrhWhC4O1uBfTZXAwDQYJKoZIhvcNAQEL
BQAwfDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJ
BgNVBAoMAk1DMQ0wCwYDVQQLDARyb290MRUwEwYDVQQDDAxyb290Y2EuYWRtaW4x
HzAdBgkqhkiG9w0BCQEWEHJvb3RjYUBhZG1pbi5jb20wIBcNMjEwNjA3MTcwNTQ3
WhgPMjEyMTA1MTQxNzA1NDdaMHwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEM
MAoGA1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEVMBMGA1UE
AwwMcm9vdGNhLmFkbWluMR8wHQYJKoZIhvcNAQkBFhByb290Y2FAYWRtaW4uY29t
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzKd0JrZR3N0A3C7Gp7sT
zLurt0pVjAIBh3N+5NsyY7eAHJWA7wRR+JpG4q6MxmYVWsk4MjsnWB0ViCCm+fTY
a9tFms6lmsjM4fJgIs8/DP+zBEOien7sD3kfddmI4ClODynNv3ODbJKyhzKQEOZ8
sdf61yWYuFzayEfNoon6BlqroPv9B0eAsgOFDndPo6vbqAFlrYAyVXx+7hmH7Hv6
8RWDaSr0uI62uhvAQeK4a+p9aTSwLcHRh1/7NezW9rzI0/7yzP3w/RS7tevDuacU
XMr3sH5xEUahGF72qYUVejUlP48fPLrdGK76QZk0M8K2EOyvuNq66P+UMialx+83
NwIDAQABo1MwUTAdBgNVHQ4EFgQU49FAwuruu1b6SdjZlxO78++5xx0wHwYDVR0j
BBgwFoAU49FAwuruu1b6SdjZlxO78++5xx0wDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAQEADfrsmYBaeV4/MTRVazsey/o0ZhBoLJ+3RFYC6+M2lYB1
yT92tbAT3787aHTw/SdFvA11oT+lMDEmBWowzZ1bp/J7tqlqMcmwL4QyhZjp0gmK
eqDXy2Jui/fOTRzWQ1ka7mR6OTWxxVoIjKVvJ/AysqGCTFMXZXrMthtCuQDG+b85
B3ALz6/j0ZFqgKzftCIuY0UnBtDEuKkAa0QkDMHLvcMAw7V/etpQPypCXqmwnc2e
vvL6cSvakEVE7rErhIeeL+1m2TBSWNrPVIvggLMv655meqkhGQn9uYyiGw6i/2V/
ngBAs4gYDvk20Cyg0kxQONmzreAdFzArud+k7FofZw==
-----END CERTIFICATE-----

@ -1,126 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDGcHX9nWsO3oQy
9HlcTQAA9RxCpVqi5MmBG2HuTipppBdXphGyhQggpD1rL5I26vdq1FIuPBlFI1pg
Hd/hw7FOr5HuQ12GZpmmPW5KIbEzeY0MVJNXOw+iUuoaQNHLQSKtV5ZOmIJURIWE
0tjicDOewW/yR9MMStOQladn7WICwwfpgLQeX9EkZqko4iOK9K6ZKUeyRf9kI/86
2M7/DAi0pxvaBGcW0F9XmBlqQu7Ma6q0fyR1qf2q3OZL3mSWuNV8S4hYyPqgKAce
s5w7zzRSNaeGX644RWU1XY8ze6Zik61aRLI2clHrI8wta8HDCdV1GvHvPj1Y7kqB
xDg0yBqpAgMBAAECggEBAJ2ipshSLcKBFylXNbUR4efgzpNOwaJW9o+eDfx9kYmb
9YMGBFb5AMzVS4kDIDaKDwOJKMNbsINQozFpafjxOL+WDunkD759cJ8ze5JeE2Md
suNRqD4KR9Ad56P1S/MXihGDW36R/i4sxJgP2oR+tzLs3R3s2oWQR2I6z+JqG4qu
tf4gDP6UIrJOirkn7TQD1VQi+8HMWx1BSER6yR86tKKTnwIlgVh0mowWXKXsB5aS
Y38Kfu+OG8FWAkCaVjFZdvg6xQcjI8MEmRqumPPf3OETrE/D6u4+qvpy1D7b8nsf
utYgv1mKYqkU0wvdDt6WTrPn/0fteLw6yMaoPmhim1ECgYEA9eFj889HojPzF7fx
67yWICah9vqd9OPYIPOtQ5rrgnTkiSxk1QyAG6i2Jl15sr8lGuVcVhTyXk/M75Ct
4gWanwbUI6khDKOM3kVN1nx/kvYFrzSuWkswB55OBEbDY/qhGu73ERNaIJdJVrY+
p5wn1sbT5I1fqAuKwpj2A5B++x0CgYEAzps6ZujBOq896QoiR4MmLEI6rzqprIsL
LHCWnGtwn4SJhPwSUD3yDbyjA5rpodjWatLtX/MV7hWlWARj/ERSOLZlU2rCPNwO
gRgGnpGcSZYhVs7WSa675OEhjmhdUmqcl88pO+14+WLN9Bj8ECqkxyD+srUe5zxo
IisJYBK/e/0CgYADI+bH5VzP2IQBSIshbJ4qOPQWmGrOBt7qxNHwrBjX6LBGhDeh
dPBp6gSxhr4YJ1LM/iLowom55KEEaj+eRF4OK+MntXBDng8dg5sT4zEp6lR2QWD8
rDsnzcDHUzQJodjO5EBpimq7QdNg9SDluRvVJWLtZ1TSa5tREu0JbJ4CjQKBgADK
kWexfoP2BdutoUH625uRyV3AcMPraGiMKdeBhdXmkQxEVuGdyx6IWWt7HWf0R6Xz
FtumN7BIvvBeW++sZ1A2Sp8OKp5HDXsrF2NmFV4myAvoEOQJWkjfH9zGw4y8QctH
DNZg63SxDy7fJZ/+OdFVbARNM0gZcCCpX4jRqZAVAoGBALz0ELUMj1s42+G6UAZ3
toBHOBI7o/4R7hRoim21dmpmyz1XJrL17wIZO4vvftNxYI4n/0U0QMFopaakMrCi
E0/I9sU9R/4MyOK0VCPtkeuxznp3xkX8zoNeewK+9EGiEZFcOpsbyRSmwjLCyTKU
G8HIMfRI71A7qj+5Me3q62K2
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIEyDCCA7CgAwIBAgIUftgGtc3lUI21xRp1xbud4eL2RGkwDQYJKoZIhvcNAQEL
BQAwgYExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDU0ZPMQsw
CQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDETMBEGA1UEAwwKcGFydG5lcjJjYTEm
MCQGCSqGSIb3DQEJARYXcGFydG5lcjJjYUBwYXJ0bmVyMi5jb20wIBcNMjEwNjA3
MTcwNTQ5WhgPMjEyMTA1MTQxNzA1NDlaMIGLMQswCQYDVQQGEwJVUzELMAkGA1UE
CAwCQ0ExDDAKBgNVBAcMA1NGTzELMAkGA1UECgwCTUMxDTALBgNVBAsMBHJvb3Qx
GDAWBgNVBAMMD3BhcnRuZXIyY2xpZW50MTErMCkGCSqGSIb3DQEJARYccGFydG5l
cjJjbGllbnQxQHBhcnRuZXIyLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAMZwdf2daw7ehDL0eVxNAAD1HEKlWqLkyYEbYe5OKmmkF1emEbKFCCCk
PWsvkjbq92rUUi48GUUjWmAd3+HDsU6vke5DXYZmmaY9bkohsTN5jQxUk1c7D6JS
6hpA0ctBIq1Xlk6YglREhYTS2OJwM57Bb/JH0wxK05CVp2ftYgLDB+mAtB5f0SRm
qSjiI4r0rpkpR7JF/2Qj/zrYzv8MCLSnG9oEZxbQX1eYGWpC7sxrqrR/JHWp/arc
5kveZJa41XxLiFjI+qAoBx6znDvPNFI1p4ZfrjhFZTVdjzN7pmKTrVpEsjZyUesj
zC1rwcMJ1XUa8e8+PVjuSoHEODTIGqkCAwEAAaOCASgwggEkMBEGCWCGSAGG+EIB
AQQEAwIGwDAdBgNVHQ4EFgQUojh+oPjTK6xgPMtbz+XEy4tl7iwwCQYDVR0TBAIw
ADAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MIG1BgNVHSMEga0wgaqAFKxchUZV+CjXbijt2NCxi2uRg9ZjoXykejB4MQswCQYD
VQQGEwJVUzELMAkGA1UECAwCQ0ExDDAKBgNVBAcMA1NGTzELMAkGA1UECgwCTUMx
DTALBgNVBAsMBHJvb3QxEDAOBgNVBAMMB2ludGVyY2ExIDAeBgkqhkiG9w0BCQEW
EWludGVyY2FAYWRtaW4uY29tghQ2eIbpK1yId7NsCpf640xyI9buOzANBgkqhkiG
9w0BAQsFAAOCAQEAbhEisOmfG5/Ks7MHu9cl17R9ISIFbMVv4wBiztLt2tWv5o5P
ul9DG2s9tBuOzs3xB4v2aZg7H2kPnUPDaTe7z5Ulc5+IyHDGSdsBzBqONH3sElue
HyZo1cOXU6nBIineYGYc0Bs9QnLRA0dmaYWZyjqB5S5GCs9Z5mk/JWzA1d110uio
RzStTpbSFlYvBpLTPShLREfFp56SMHDEaHBIoVERzfULvQwZLDsIAyqE/W+WE0FF
Lxhz3jxvztoOE6Sr5cmOp7nuwo3ALlWOjFCHOZRs/1qDDnIgXFnPKsZohtvVK2TG
a+/zW8wRyAAo4FgBTfqICXpOtK+Yg479Aj2GbQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID8DCCAtigAwIBAgIUNniG6StciHezbAqX+uNMciPW7jswDQYJKoZIhvcNAQEL
BQAweDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJ
BgNVBAoMAk1DMQ0wCwYDVQQLDARyb290MRAwDgYDVQQDDAdpbnRlcmNhMSAwHgYJ
KoZIhvcNAQkBFhFpbnRlcmNhQGFkbWluLmNvbTAgFw0yMTA2MDcxNzA1NDlaGA8y
MTIxMDUxNDE3MDU0OVowgYExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoG
A1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDETMBEGA1UEAwwK
cGFydG5lcjJjYTEmMCQGCSqGSIb3DQEJARYXcGFydG5lcjJjYUBwYXJ0bmVyMi5j
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLvHvIuFFYmNYEA6P2
/RB3LBDpxbnjl7SU4KCWcfBxQ1guw3aG/HzjenKt3m6UmmESFSh0k4/a/s9m4z/M
ubVqrm0ll2HvyodetFL40jLgSCIbP3taCIhLptaOCB2P6keYEfjGdb5YTNMgCqYk
NYA+dgXtw1VMJvI7aRpmVOIPtQx/nqncigYzxykGlTbeusSPAGp7CAmxTZSJUFLI
ig0ReaKSopiQE2j/ljJXFK26sMlkq3Lw41E4fPju+PBeubeb6eT8fzhn0IaCgTeO
cZgKzVUv3MsrrKfDHXUhGAspKBGDkqkrogZ6UYcvyCLfnRM0vVGc1L7oaFnMMZ1m
NYRpAgMBAAGjZjBkMB0GA1UdDgQWBBSsXIVGVfgo124o7djQsYtrkYPWYzAfBgNV
HSMEGDAWgBT8BlnPk8BS8+JHlIEoCp3sO8jDDjASBgNVHRMBAf8ECDAGAQH/AgEA
MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABSHI1SgQ1FBWmPRZ
nXDspyvbvPsjk/p6erUVGGuDyy/F2rJldz7musNCL5ijAmlQfYPNMNoLU1BR+fAl
WSYfdjL1mMygXtj/KlaNqM5hQMUfyYa4Yk1ODaScl+wfIsSmzTSl/j4fMf58GYpr
9rssVveQrFAipeWhxgGqQNJooAbqmZKE4tePhKzrsH+B2hDEUnFptkasnQEkQQEZ
rSzJlU72U8p3Gwq9t9rKYoBLSr0yoBbh4fdFcPsuN/mZS6TNEu1Uc4ui9eWheGTM
RCNGehiXAczfIhf9WfMfyNhp5/pZc2nTeV/LsSjuCFXUdoL5rAESPcHBc56vXtcV
1ywC0A==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID6jCCAtKgAwIBAgIUTwPfI+2FxYq0V6uukemLf67qANowDQYJKoZIhvcNAQEL
BQAwfDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJ
BgNVBAoMAk1DMQ0wCwYDVQQLDARyb290MRUwEwYDVQQDDAxyb290Y2EuYWRtaW4x
HzAdBgkqhkiG9w0BCQEWEHJvb3RjYUBhZG1pbi5jb20wIBcNMjEwNjA3MTcwNTQ3
WhgPMjEyMTA1MTQxNzA1NDdaMHgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEM
MAoGA1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEQMA4GA1UE
AwwHaW50ZXJjYTEgMB4GCSqGSIb3DQEJARYRaW50ZXJjYUBhZG1pbi5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxuUWq2F6MFQLeFVBB800pjiJv
pqrpMb8lv5aEOX87slRRkIVe0M/6mSlNvJSSclGindIhsWxaYD4Kend+o+ODhMqT
Jl7zvVTTluGg8SK22kyJ8DTWHnhnFhpoKVLc5qjgvglOf0h7S9F/tL5AkpGoBq7t
PkbOJPxKR7bvn34Iux3HgS1uzwZqHSYBcNHuYB6PSgyQJiNLIrA/019YqqUI5R+W
V/Nb/kkrnsUS+hU6ntAtewus0irO+4fJzBlpN+bvbEBdVHeVmIYhF6ILxtCGWX5l
lOlDrYNXiff0ksKtEvyUV/NFOASixEBMQ88Un7NGHR8y1NW3fCGiVkOhvaprAgMB
AAGjZjBkMB0GA1UdDgQWBBT8BlnPk8BS8+JHlIEoCp3sO8jDDjAfBgNVHSMEGDAW
gBTj0UDC6u67VvpJ2NmXE7vz77nHHTASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1Ud
DwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAZYQg0VUOQ1DGoU0y0TsTzAZ4
IEy5xavV7Nma9AJI0ZVFpqGEBjTXjxi7r/co1EREN3bi7QnZfJhU4SGVZ0T7wq+p
/S3x16DEPEufa3JmP+brBPOOP/5EJX5+2BXMUWuDcY7MAokaAIAudjmVk32FoZgy
54FkZ+YRillU++7k0ie8EEYE8pN2ABIqNCdHxGEhwEc0wVwB6bBONmcEssYmipUh
DQH6+sfKBcd+sUMGG3qd79sE7BF9w8bAHhKcBm5eTdEks9jh6H1o0PgBvFP8fFzF
q89KGuLw7T0n/Khkmrv5cifwmTpg42Ivorv8qk02aeiOAGiMyFFJ38BQtH64LQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID2zCCAsOgAwIBAgIURc832yfuirkVrhWhC4O1uBfTZXAwDQYJKoZIhvcNAQEL
BQAwfDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTRk8xCzAJ
BgNVBAoMAk1DMQ0wCwYDVQQLDARyb290MRUwEwYDVQQDDAxyb290Y2EuYWRtaW4x
HzAdBgkqhkiG9w0BCQEWEHJvb3RjYUBhZG1pbi5jb20wIBcNMjEwNjA3MTcwNTQ3
WhgPMjEyMTA1MTQxNzA1NDdaMHwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEM
MAoGA1UEBwwDU0ZPMQswCQYDVQQKDAJNQzENMAsGA1UECwwEcm9vdDEVMBMGA1UE
AwwMcm9vdGNhLmFkbWluMR8wHQYJKoZIhvcNAQkBFhByb290Y2FAYWRtaW4uY29t
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzKd0JrZR3N0A3C7Gp7sT
zLurt0pVjAIBh3N+5NsyY7eAHJWA7wRR+JpG4q6MxmYVWsk4MjsnWB0ViCCm+fTY
a9tFms6lmsjM4fJgIs8/DP+zBEOien7sD3kfddmI4ClODynNv3ODbJKyhzKQEOZ8
sdf61yWYuFzayEfNoon6BlqroPv9B0eAsgOFDndPo6vbqAFlrYAyVXx+7hmH7Hv6
8RWDaSr0uI62uhvAQeK4a+p9aTSwLcHRh1/7NezW9rzI0/7yzP3w/RS7tevDuacU
XMr3sH5xEUahGF72qYUVejUlP48fPLrdGK76QZk0M8K2EOyvuNq66P+UMialx+83
NwIDAQABo1MwUTAdBgNVHQ4EFgQU49FAwuruu1b6SdjZlxO78++5xx0wHwYDVR0j
BBgwFoAU49FAwuruu1b6SdjZlxO78++5xx0wDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAQEADfrsmYBaeV4/MTRVazsey/o0ZhBoLJ+3RFYC6+M2lYB1
yT92tbAT3787aHTw/SdFvA11oT+lMDEmBWowzZ1bp/J7tqlqMcmwL4QyhZjp0gmK
eqDXy2Jui/fOTRzWQ1ka7mR6OTWxxVoIjKVvJ/AysqGCTFMXZXrMthtCuQDG+b85
B3ALz6/j0ZFqgKzftCIuY0UnBtDEuKkAa0QkDMHLvcMAw7V/etpQPypCXqmwnc2e
vvL6cSvakEVE7rErhIeeL+1m2TBSWNrPVIvggLMv655meqkhGQn9uYyiGw6i/2V/
ngBAs4gYDvk20Cyg0kxQONmzreAdFzArud+k7FofZw==
-----END CERTIFICATE-----

@ -60,7 +60,6 @@ include 'evm'
include 'metrics:core'
include 'metrics:rocksdb'
include 'nat'
include 'pki'
include 'platform'
include 'plugin-api'
include 'plugins:rocksdb'

Loading…
Cancel
Save