mirror of https://github.com/hyperledger/besu
removed tests for pki qbft and add deprecation notice (#6979)
* removed tests for pki qbft and add deprecation notice Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com> * remove more PKI and CMS creation utils from tests Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com> --------- Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>pull/7059/head 24.4.0-RC3
parent
e4df70a350
commit
12723ace68
@ -1,196 +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.tests.acceptance.dsl.node.configuration.pki; |
|
||||||
|
|
||||||
import static org.hyperledger.besu.pki.util.TestCertificateUtils.createKeyPair; |
|
||||||
import static org.hyperledger.besu.pki.util.TestCertificateUtils.createSelfSignedCertificate; |
|
||||||
import static org.hyperledger.besu.pki.util.TestCertificateUtils.issueCertificate; |
|
||||||
|
|
||||||
import org.hyperledger.besu.pki.config.PkiKeyStoreConfiguration; |
|
||||||
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper; |
|
||||||
import org.hyperledger.besu.pki.util.TestCertificateUtils; |
|
||||||
|
|
||||||
import java.io.FileOutputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.nio.charset.StandardCharsets; |
|
||||||
import java.nio.file.Files; |
|
||||||
import java.nio.file.Path; |
|
||||||
import java.security.KeyPair; |
|
||||||
import java.security.KeyStore; |
|
||||||
import java.security.cert.Certificate; |
|
||||||
import java.security.cert.X509Certificate; |
|
||||||
import java.time.Instant; |
|
||||||
import java.time.temporal.ChronoUnit; |
|
||||||
import java.util.Objects; |
|
||||||
import java.util.UUID; |
|
||||||
|
|
||||||
public class PkiKeystoreConfigurationFactory { |
|
||||||
|
|
||||||
/* |
|
||||||
PKCS11 config files |
|
||||||
*/ |
|
||||||
final String NSSCONFIG_PATH_STRING = "/pki-certs/%s/nss.cfg"; |
|
||||||
final String NSSPIN_PATH_STRING = "/pki-certs/%s/nsspin.txt"; |
|
||||||
final String TRUSTSTORE_PATH_STRING = "/pki-certs/%s/truststore.p12"; |
|
||||||
final String CRL_PATH_STRING = "/pki-certs/crl/crl.pem"; |
|
||||||
|
|
||||||
/* |
|
||||||
Software keystore config |
|
||||||
*/ |
|
||||||
public static final String KEYSTORE_DEFAULT_PASSWORD = "password"; |
|
||||||
|
|
||||||
private KeyPair caKeyPair; |
|
||||||
private X509Certificate caCertificate; |
|
||||||
private Path trustStoreFile; |
|
||||||
private Path passwordFile; |
|
||||||
|
|
||||||
public PkiKeyStoreConfiguration createPkiConfig(final String type, final String name) { |
|
||||||
if (KeyStoreWrapper.KEYSTORE_TYPE_PKCS11.equals(type)) { |
|
||||||
return createPKCS11PkiConfig(name); |
|
||||||
} else { |
|
||||||
return createSoftwareKeyStorePkiConfig(type, name); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private PkiKeyStoreConfiguration createPKCS11PkiConfig(final String name) { |
|
||||||
final PkiKeyStoreConfiguration.Builder pkiKeyStoreConfigBuilder = |
|
||||||
new PkiKeyStoreConfiguration.Builder(); |
|
||||||
|
|
||||||
try { |
|
||||||
pkiKeyStoreConfigBuilder |
|
||||||
.withKeyStoreType(KeyStoreWrapper.KEYSTORE_TYPE_PKCS11) |
|
||||||
.withKeyStorePath( |
|
||||||
PKCS11Utils.initNSSConfigFile( |
|
||||||
readResourceAsPath(String.format(NSSCONFIG_PATH_STRING, name)))) |
|
||||||
.withKeyStorePasswordPath(readResourceAsPath(String.format(NSSPIN_PATH_STRING, name))) |
|
||||||
.withTrustStoreType(KeyStoreWrapper.KEYSTORE_TYPE_PKCS12) |
|
||||||
.withTrustStorePath(readResourceAsPath(String.format(TRUSTSTORE_PATH_STRING, name))) |
|
||||||
.withTrustStorePasswordPath(readResourceAsPath(String.format(NSSPIN_PATH_STRING, name))) |
|
||||||
.withCrlFilePath(readResourceAsPath(CRL_PATH_STRING)) |
|
||||||
.withCertificateAlias(name); |
|
||||||
|
|
||||||
} catch (Exception e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
|
|
||||||
return pkiKeyStoreConfigBuilder.build(); |
|
||||||
} |
|
||||||
|
|
||||||
private PkiKeyStoreConfiguration createSoftwareKeyStorePkiConfig( |
|
||||||
final String type, final String name) { |
|
||||||
PkiKeyStoreConfiguration.Builder pkiKeyStoreConfigBuilder = |
|
||||||
new PkiKeyStoreConfiguration.Builder(); |
|
||||||
|
|
||||||
pkiKeyStoreConfigBuilder.withTrustStoreType(type); |
|
||||||
pkiKeyStoreConfigBuilder.withTrustStorePath(createTrustStore(type)); |
|
||||||
pkiKeyStoreConfigBuilder.withTrustStorePasswordPath(passwordFile); |
|
||||||
|
|
||||||
pkiKeyStoreConfigBuilder.withKeyStoreType(type); |
|
||||||
pkiKeyStoreConfigBuilder.withKeyStorePath(createKeyStore(type, name)); |
|
||||||
pkiKeyStoreConfigBuilder.withKeyStorePasswordPath(passwordFile); |
|
||||||
|
|
||||||
pkiKeyStoreConfigBuilder.withCertificateAlias(name); |
|
||||||
|
|
||||||
return pkiKeyStoreConfigBuilder.build(); |
|
||||||
} |
|
||||||
|
|
||||||
private Path createTrustStore(final String type) { |
|
||||||
// Only create the truststore if this is the first time this method is being called
|
|
||||||
if (caKeyPair == null) { |
|
||||||
try { |
|
||||||
caKeyPair = createKeyPair(TestCertificateUtils.Algorithm.RSA); |
|
||||||
caCertificate = createSelfSignedCertificate("ca", notBefore(), notAfter(), caKeyPair); |
|
||||||
|
|
||||||
final KeyStore truststore = KeyStore.getInstance(type); |
|
||||||
truststore.load(null, null); |
|
||||||
truststore.setCertificateEntry("ca", caCertificate); |
|
||||||
|
|
||||||
final String uniqueId = UUID.randomUUID().toString(); |
|
||||||
trustStoreFile = writeKeyStoreFile(truststore, "truststore", uniqueId); |
|
||||||
passwordFile = writePasswordFile(KEYSTORE_DEFAULT_PASSWORD, "password", uniqueId); |
|
||||||
} catch (final Exception e) { |
|
||||||
throw new RuntimeException("Error creating truststore for Acceptance Test", e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return trustStoreFile; |
|
||||||
} |
|
||||||
|
|
||||||
private Path createKeyStore(final String type, final String alias) { |
|
||||||
if (caKeyPair == null) { |
|
||||||
createTrustStore(type); |
|
||||||
} |
|
||||||
|
|
||||||
final KeyPair kp = createKeyPair(TestCertificateUtils.Algorithm.RSA); |
|
||||||
final X509Certificate certificate = |
|
||||||
issueCertificate(caCertificate, caKeyPair, "validator", notBefore(), notAfter(), kp, false); |
|
||||||
|
|
||||||
try { |
|
||||||
final KeyStore keyStore = KeyStore.getInstance(type); |
|
||||||
keyStore.load(null, null); |
|
||||||
keyStore.setKeyEntry( |
|
||||||
alias, |
|
||||||
kp.getPrivate(), |
|
||||||
KEYSTORE_DEFAULT_PASSWORD.toCharArray(), |
|
||||||
new Certificate[] {certificate, caCertificate}); |
|
||||||
|
|
||||||
final String id = UUID.randomUUID().toString(); |
|
||||||
return writeKeyStoreFile(keyStore, "keystore", id); |
|
||||||
} catch (final Exception e) { |
|
||||||
throw new RuntimeException("Error creating keystore for Acceptance Test", e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private Path writeKeyStoreFile( |
|
||||||
final KeyStore keyStore, final String prefix, final String suffix) { |
|
||||||
try { |
|
||||||
final Path file = Files.createTempFile(prefix, suffix != null ? suffix : ""); |
|
||||||
file.toFile().deleteOnExit(); |
|
||||||
final FileOutputStream keyStoreFOS = new FileOutputStream(file.toFile()); |
|
||||||
keyStore.store(keyStoreFOS, KEYSTORE_DEFAULT_PASSWORD.toCharArray()); |
|
||||||
|
|
||||||
return file; |
|
||||||
} catch (final Exception e) { |
|
||||||
throw new RuntimeException("Error creating keystore file", e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private Path writePasswordFile(final String password, final String prefix, final String suffix) { |
|
||||||
try { |
|
||||||
final Path file = Files.createTempFile(prefix, suffix); |
|
||||||
file.toFile().deleteOnExit(); |
|
||||||
Files.write(file, password.getBytes(StandardCharsets.UTF_8)); |
|
||||||
return file; |
|
||||||
} catch (final IOException e) { |
|
||||||
throw new RuntimeException("Error creating password file", e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private Instant notBefore() { |
|
||||||
return Instant.now().minus(1, ChronoUnit.DAYS); |
|
||||||
} |
|
||||||
|
|
||||||
private Instant notAfter() { |
|
||||||
return Instant.now().plus(10, ChronoUnit.DAYS); |
|
||||||
} |
|
||||||
|
|
||||||
private Path readResourceAsPath(final String path) throws Exception { |
|
||||||
return Path.of(Objects.requireNonNull(this.getClass().getResource(path)).toURI()); |
|
||||||
} |
|
||||||
} |
|
@ -1,29 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2020 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.tests.acceptance.bft.pki; |
|
||||||
|
|
||||||
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBaseJunit5; |
|
||||||
|
|
||||||
import java.util.stream.Stream; |
|
||||||
|
|
||||||
import org.junit.jupiter.api.Disabled; |
|
||||||
import org.junit.jupiter.params.provider.Arguments; |
|
||||||
|
|
||||||
@Disabled("This is not a test class, it offers PKI QBFT parameterization only.") |
|
||||||
public abstract class ParameterizedPkiQbftTestBase extends AcceptanceTestBaseJunit5 { |
|
||||||
public static Stream<Arguments> factoryFunctions() { |
|
||||||
return PkiQbftAcceptanceTestParameterization.getFactories(); |
|
||||||
} |
|
||||||
} |
|
@ -1,130 +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.tests.acceptance.bft.pki; |
|
||||||
|
|
||||||
import org.hyperledger.besu.tests.acceptance.dsl.account.Account; |
|
||||||
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; |
|
||||||
|
|
||||||
import org.junit.jupiter.params.ParameterizedTest; |
|
||||||
import org.junit.jupiter.params.provider.MethodSource; |
|
||||||
|
|
||||||
public class PkiQbftAcceptanceTest extends ParameterizedPkiQbftTestBase { |
|
||||||
|
|
||||||
@ParameterizedTest(name = "{index}: {0}") |
|
||||||
@MethodSource("factoryFunctions") |
|
||||||
public void shouldMineOnSingleNode( |
|
||||||
final String testName, final PkiQbftAcceptanceTestParameterization nodeFactory) |
|
||||||
throws Exception { |
|
||||||
final BesuNode minerNode = nodeFactory.createNode(besu, "miner1"); |
|
||||||
cluster.start(minerNode); |
|
||||||
|
|
||||||
cluster.verify(blockchain.reachesHeight(minerNode, 1)); |
|
||||||
|
|
||||||
final Account sender = accounts.createAccount("account1"); |
|
||||||
final Account receiver = accounts.createAccount("account2"); |
|
||||||
|
|
||||||
minerNode.execute(accountTransactions.createTransfer(sender, 50)); |
|
||||||
cluster.verify(sender.balanceEquals(50)); |
|
||||||
|
|
||||||
minerNode.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 1)); |
|
||||||
cluster.verify(receiver.balanceEquals(1)); |
|
||||||
|
|
||||||
minerNode.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 2)); |
|
||||||
cluster.verify(receiver.balanceEquals(3)); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest(name = "{index}: {0}") |
|
||||||
@MethodSource("factoryFunctions") |
|
||||||
public void shouldMineOnMultipleNodes( |
|
||||||
final String testName, final PkiQbftAcceptanceTestParameterization nodeFactory) |
|
||||||
throws Exception { |
|
||||||
final BesuNode minerNode1 = nodeFactory.createNode(besu, "miner1"); |
|
||||||
final BesuNode minerNode2 = nodeFactory.createNode(besu, "miner2"); |
|
||||||
final BesuNode minerNode3 = nodeFactory.createNode(besu, "miner3"); |
|
||||||
final BesuNode minerNode4 = nodeFactory.createNode(besu, "miner4"); |
|
||||||
cluster.start(minerNode1, minerNode2, minerNode3, minerNode4); |
|
||||||
|
|
||||||
cluster.verify(blockchain.reachesHeight(minerNode1, 1, 85)); |
|
||||||
|
|
||||||
final Account sender = accounts.createAccount("account1"); |
|
||||||
final Account receiver = accounts.createAccount("account2"); |
|
||||||
|
|
||||||
minerNode1.execute(accountTransactions.createTransfer(sender, 50)); |
|
||||||
cluster.verify(sender.balanceEquals(50)); |
|
||||||
|
|
||||||
minerNode2.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 1)); |
|
||||||
cluster.verify(receiver.balanceEquals(1)); |
|
||||||
|
|
||||||
minerNode3.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 2)); |
|
||||||
cluster.verify(receiver.balanceEquals(3)); |
|
||||||
|
|
||||||
minerNode4.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 3)); |
|
||||||
cluster.verify(receiver.balanceEquals(6)); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest(name = "{index}: {0}") |
|
||||||
@MethodSource("factoryFunctions") |
|
||||||
public void shouldMineWithIgnoringANodeInCRL( |
|
||||||
final String testName, final PkiQbftAcceptanceTestParameterization nodeFactory) |
|
||||||
throws Exception { |
|
||||||
final BesuNode minerNode1 = nodeFactory.createNode(besu, "miner1"); |
|
||||||
final BesuNode minerNode2 = nodeFactory.createNode(besu, "miner2"); |
|
||||||
final BesuNode minerNode3 = nodeFactory.createNode(besu, "miner3"); |
|
||||||
final BesuNode minerNode4 = nodeFactory.createNode(besu, "miner4"); |
|
||||||
final BesuNode minerNode5 = nodeFactory.createNode(besu, "miner5"); |
|
||||||
final BesuNode minerNode6 = nodeFactory.createNode(besu, "miner6"); |
|
||||||
try { |
|
||||||
cluster.start(minerNode1, minerNode2, minerNode3, minerNode4); |
|
||||||
|
|
||||||
cluster.startNode(minerNode5); |
|
||||||
cluster.startNode(minerNode6); |
|
||||||
|
|
||||||
cluster.verify(blockchain.reachesHeight(minerNode1, 1, 85)); |
|
||||||
|
|
||||||
final Account sender = accounts.createAccount("account1"); |
|
||||||
final Account receiver = accounts.createAccount("account2"); |
|
||||||
|
|
||||||
minerNode1.execute(accountTransactions.createTransfer(sender, 50)); |
|
||||||
cluster.verify(sender.balanceEquals(50)); |
|
||||||
|
|
||||||
minerNode2.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 1)); |
|
||||||
cluster.verify(receiver.balanceEquals(1)); |
|
||||||
|
|
||||||
minerNode3.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 2)); |
|
||||||
cluster.verify(receiver.balanceEquals(3)); |
|
||||||
|
|
||||||
minerNode4.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 3)); |
|
||||||
cluster.verify(receiver.balanceEquals(6)); |
|
||||||
|
|
||||||
if (minerNode1.getTLSConfiguration().isEmpty()) { |
|
||||||
minerNode1.verify(net.awaitPeerCount(5)); |
|
||||||
minerNode5.verify(net.awaitPeerCount(5)); |
|
||||||
minerNode6.verify(net.awaitPeerCount(5)); |
|
||||||
} else { |
|
||||||
minerNode1.verify(net.awaitPeerCount(3)); |
|
||||||
minerNode5.verify(net.awaitPeerCount(0)); |
|
||||||
minerNode6.verify(net.awaitPeerCount(0)); |
|
||||||
} |
|
||||||
} finally { |
|
||||||
cluster.stopNode(minerNode5); |
|
||||||
cluster.stopNode(minerNode6); |
|
||||||
minerNode5.close(); |
|
||||||
minerNode6.close(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,120 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2020 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.tests.acceptance.bft.pki; |
|
||||||
|
|
||||||
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; |
|
||||||
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.BesuNodeFactory; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
import java.util.stream.Stream; |
|
||||||
|
|
||||||
import org.junit.jupiter.params.provider.Arguments; |
|
||||||
|
|
||||||
public class PkiQbftAcceptanceTestParameterization { |
|
||||||
|
|
||||||
public static Stream<Arguments> getFactories() { |
|
||||||
List<Arguments> args = new ArrayList<>(); |
|
||||||
|
|
||||||
/* |
|
||||||
BLOCK CREATION |
|
||||||
*/ |
|
||||||
|
|
||||||
args.add( |
|
||||||
Arguments.of( |
|
||||||
"qbft-pki-jks", |
|
||||||
new PkiQbftAcceptanceTestParameterization( |
|
||||||
BesuNodeFactory::createPkiQbftJKSNode, |
|
||||||
BesuNodeFactory::createPkiQbftJKSNodeWithValidators))); |
|
||||||
|
|
||||||
args.add( |
|
||||||
Arguments.of( |
|
||||||
"qbft-pki-pkcs12", |
|
||||||
new PkiQbftAcceptanceTestParameterization( |
|
||||||
BesuNodeFactory::createPkiQbftPKCS12Node, |
|
||||||
BesuNodeFactory::createPkiQbftPKCS12NodeWithValidators))); |
|
||||||
|
|
||||||
if (Boolean.getBoolean("acctests.runBesuAsProcess")) { |
|
||||||
args.add( |
|
||||||
Arguments.of( |
|
||||||
"qbft-pki-pkcs11", |
|
||||||
new PkiQbftAcceptanceTestParameterization( |
|
||||||
BesuNodeFactory::createPkiQbftPKCS11Node, |
|
||||||
BesuNodeFactory::createPkiQbftPKCS11NodeWithValidators))); |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
TLS |
|
||||||
*/ |
|
||||||
|
|
||||||
args.add( |
|
||||||
Arguments.of( |
|
||||||
"qbft-tls-jks", |
|
||||||
new PkiQbftAcceptanceTestParameterization( |
|
||||||
BesuNodeFactory::createQbftNodeWithTLSJKS, |
|
||||||
BesuNodeFactory::createQbftTLSJKSNodeWithValidators))); |
|
||||||
|
|
||||||
args.add( |
|
||||||
Arguments.of( |
|
||||||
"qbft-tls-pkcs12", |
|
||||||
new PkiQbftAcceptanceTestParameterization( |
|
||||||
BesuNodeFactory::createQbftNodeWithTLSPKCS12, |
|
||||||
BesuNodeFactory::createQbftTLSPKCS12NodeWithValidators))); |
|
||||||
|
|
||||||
if (Boolean.getBoolean("acctests.runBesuAsProcess")) { |
|
||||||
args.add( |
|
||||||
Arguments.of( |
|
||||||
"qbft-tls-pkcs11", |
|
||||||
new PkiQbftAcceptanceTestParameterization( |
|
||||||
BesuNodeFactory::createQbftNodeWithTLSPKCS11, |
|
||||||
BesuNodeFactory::createQbftTLSPKCS11NodeWithValidators))); |
|
||||||
} |
|
||||||
|
|
||||||
return args.stream(); |
|
||||||
} |
|
||||||
|
|
||||||
@FunctionalInterface |
|
||||||
public interface NodeCreator { |
|
||||||
|
|
||||||
BesuNode create(BesuNodeFactory factory, String name) throws Exception; |
|
||||||
} |
|
||||||
|
|
||||||
@FunctionalInterface |
|
||||||
public interface NodeWithValidatorsCreator { |
|
||||||
|
|
||||||
BesuNode create(BesuNodeFactory factory, String name, String[] validators) throws Exception; |
|
||||||
} |
|
||||||
|
|
||||||
private final NodeCreator creatorFn; |
|
||||||
private final NodeWithValidatorsCreator createorWithValidatorFn; |
|
||||||
|
|
||||||
public PkiQbftAcceptanceTestParameterization( |
|
||||||
final NodeCreator creatorFn, final NodeWithValidatorsCreator createorWithValidatorFn) { |
|
||||||
this.creatorFn = creatorFn; |
|
||||||
this.createorWithValidatorFn = createorWithValidatorFn; |
|
||||||
} |
|
||||||
|
|
||||||
public BesuNode createNode(BesuNodeFactory factory, String name) throws Exception { |
|
||||||
return creatorFn.create(factory, name); |
|
||||||
} |
|
||||||
|
|
||||||
public BesuNode createNodeWithValidators( |
|
||||||
BesuNodeFactory factory, String name, String[] validators) throws Exception { |
|
||||||
return createorWithValidatorFn.create(factory, name, validators); |
|
||||||
} |
|
||||||
} |
|
@ -1,162 +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.consensus.qbft.blockcreation; |
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat; |
|
||||||
import static org.assertj.core.api.Assertions.assertThatThrownBy; |
|
||||||
import static org.hyperledger.besu.consensus.common.bft.BftExtraDataFixture.createExtraData; |
|
||||||
import static org.mockito.ArgumentMatchers.any; |
|
||||||
import static org.mockito.ArgumentMatchers.anyLong; |
|
||||||
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.consensus.common.bft.BftBlockHeaderFunctions; |
|
||||||
import org.hyperledger.besu.consensus.common.bft.BftExtraData; |
|
||||||
import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule; |
|
||||||
import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; |
|
||||||
import org.hyperledger.besu.consensus.qbft.pki.PkiQbftBlockHeaderFunctions; |
|
||||||
import org.hyperledger.besu.consensus.qbft.pki.PkiQbftExtraData; |
|
||||||
import org.hyperledger.besu.consensus.qbft.pki.PkiQbftExtraDataCodec; |
|
||||||
import org.hyperledger.besu.datatypes.Hash; |
|
||||||
import org.hyperledger.besu.ethereum.blockcreation.BlockCreationTiming; |
|
||||||
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator; |
|
||||||
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult; |
|
||||||
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults; |
|
||||||
import org.hyperledger.besu.ethereum.core.Block; |
|
||||||
import org.hyperledger.besu.ethereum.core.BlockBody; |
|
||||||
import org.hyperledger.besu.ethereum.core.BlockHeader; |
|
||||||
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; |
|
||||||
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; |
|
||||||
import org.hyperledger.besu.ethereum.mainnet.WithdrawalsValidator; |
|
||||||
import org.hyperledger.besu.pki.cms.CmsCreator; |
|
||||||
|
|
||||||
import java.util.Collections; |
|
||||||
|
|
||||||
import org.apache.tuweni.bytes.Bytes; |
|
||||||
import org.junit.jupiter.api.BeforeEach; |
|
||||||
import org.junit.jupiter.api.Test; |
|
||||||
|
|
||||||
public class PkiQbftBlockCreatorTest { |
|
||||||
|
|
||||||
private final PkiQbftExtraDataCodec extraDataCodec = new PkiQbftExtraDataCodec(); |
|
||||||
|
|
||||||
private BlockCreator blockCreator; |
|
||||||
private CmsCreator cmsCreator; |
|
||||||
private PkiQbftBlockCreator pkiQbftBlockCreator; |
|
||||||
private BlockHeaderTestFixture blockHeaderBuilder; |
|
||||||
private BlockHeader blockHeader; |
|
||||||
private BftProtocolSchedule protocolSchedule; |
|
||||||
private ProtocolSpec protocolSpec; |
|
||||||
|
|
||||||
@BeforeEach |
|
||||||
public void before() { |
|
||||||
blockCreator = mock(BlockCreator.class); |
|
||||||
cmsCreator = mock(CmsCreator.class); |
|
||||||
blockHeader = mock(BlockHeader.class); |
|
||||||
protocolSchedule = mock(BftProtocolSchedule.class); |
|
||||||
protocolSpec = mock(ProtocolSpec.class); |
|
||||||
|
|
||||||
pkiQbftBlockCreator = |
|
||||||
new PkiQbftBlockCreator( |
|
||||||
blockCreator, cmsCreator, extraDataCodec, blockHeader, protocolSchedule); |
|
||||||
|
|
||||||
blockHeaderBuilder = new BlockHeaderTestFixture(); |
|
||||||
|
|
||||||
when(protocolSchedule.getByBlockNumberOrTimestamp(anyLong(), anyLong())) |
|
||||||
.thenReturn(protocolSpec); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void createProposalBehaviourWithNonPkiCodecFails() { |
|
||||||
assertThatThrownBy( |
|
||||||
() -> |
|
||||||
new PkiQbftBlockCreator( |
|
||||||
blockCreator, |
|
||||||
cmsCreator, |
|
||||||
new QbftExtraDataCodec(), |
|
||||||
blockHeader, |
|
||||||
protocolSchedule)) |
|
||||||
.isInstanceOf(IllegalArgumentException.class) |
|
||||||
.hasMessageContaining("PkiQbftBlockCreator must use PkiQbftExtraDataCodec"); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void cmsInProposedBlockHasValueCreatedByCmsCreator() { |
|
||||||
createBlockBeingProposed(); |
|
||||||
when(protocolSpec.getWithdrawalsValidator()) |
|
||||||
.thenReturn(new WithdrawalsValidator.AllowedWithdrawals()); |
|
||||||
|
|
||||||
final Bytes cms = Bytes.random(32); |
|
||||||
when(cmsCreator.create(any(Bytes.class))).thenReturn(cms); |
|
||||||
|
|
||||||
final Block proposedBlock = pkiQbftBlockCreator.createBlock(1L).getBlock(); |
|
||||||
|
|
||||||
final PkiQbftExtraData proposedBlockExtraData = |
|
||||||
(PkiQbftExtraData) extraDataCodec.decodeRaw(proposedBlock.getHeader().getExtraData()); |
|
||||||
assertThat(proposedBlockExtraData).isInstanceOf(PkiQbftExtraData.class); |
|
||||||
assertThat(proposedBlockExtraData.getCms()).isEqualTo(cms); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void cmsIsCreatedWithCorrectHashingFunction() { |
|
||||||
when(protocolSpec.getWithdrawalsValidator()) |
|
||||||
.thenReturn(new WithdrawalsValidator.ProhibitedWithdrawals()); |
|
||||||
final Block block = createBlockBeingProposed(); |
|
||||||
final Hash expectedHashForCmsCreation = |
|
||||||
PkiQbftBlockHeaderFunctions.forCmsSignature(extraDataCodec).hash(block.getHeader()); |
|
||||||
|
|
||||||
when(cmsCreator.create(any(Bytes.class))).thenReturn(Bytes.random(32)); |
|
||||||
|
|
||||||
pkiQbftBlockCreator.createBlock(1L); |
|
||||||
|
|
||||||
verify(cmsCreator).create(eq(expectedHashForCmsCreation)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void proposedBlockHashUsesCommittedSealHeaderFunction() { |
|
||||||
createBlockBeingProposed(); |
|
||||||
when(cmsCreator.create(any(Bytes.class))).thenReturn(Bytes.random(32)); |
|
||||||
|
|
||||||
final Block blockWithCms = pkiQbftBlockCreator.createBlock(1L).getBlock(); |
|
||||||
|
|
||||||
final Hash expectedBlockHash = |
|
||||||
BftBlockHeaderFunctions.forCommittedSeal(extraDataCodec).hash(blockWithCms.getHeader()); |
|
||||||
|
|
||||||
assertThat(blockWithCms.getHash()).isEqualTo(expectedBlockHash); |
|
||||||
} |
|
||||||
|
|
||||||
private Block createBlockBeingProposed() { |
|
||||||
final BftExtraData originalExtraData = |
|
||||||
createExtraData(blockHeaderBuilder.buildHeader(), extraDataCodec); |
|
||||||
final BlockHeader blockHeaderWithExtraData = |
|
||||||
blockHeaderBuilder.extraData(extraDataCodec.encode(originalExtraData)).buildHeader(); |
|
||||||
final Block block = |
|
||||||
new Block( |
|
||||||
blockHeaderWithExtraData, |
|
||||||
new BlockBody(Collections.emptyList(), Collections.emptyList())); |
|
||||||
when(blockCreator.createBlock(eq(1L))) |
|
||||||
.thenReturn( |
|
||||||
new BlockCreationResult( |
|
||||||
block, new TransactionSelectionResults(), new BlockCreationTiming())); |
|
||||||
when(blockCreator.createEmptyWithdrawalsBlock(anyLong())) |
|
||||||
.thenReturn( |
|
||||||
new BlockCreationResult( |
|
||||||
block, new TransactionSelectionResults(), new BlockCreationTiming())); |
|
||||||
|
|
||||||
return block; |
|
||||||
} |
|
||||||
} |
|
@ -1,85 +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.consensus.qbft.pki; |
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.eq; |
|
||||||
import static org.mockito.Mockito.verify; |
|
||||||
import static org.mockito.Mockito.verifyNoInteractions; |
|
||||||
|
|
||||||
import org.hyperledger.besu.consensus.qbft.pki.DefaultKeyStoreWrapperProvider.HardwareKeyStoreWrapperProvider; |
|
||||||
import org.hyperledger.besu.consensus.qbft.pki.DefaultKeyStoreWrapperProvider.SoftwareKeyStoreWrapperProvider; |
|
||||||
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper; |
|
||||||
|
|
||||||
import java.nio.file.Path; |
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test; |
|
||||||
import org.junit.jupiter.api.extension.ExtendWith; |
|
||||||
import org.mockito.InjectMocks; |
|
||||||
import org.mockito.Mock; |
|
||||||
import org.mockito.junit.jupiter.MockitoExtension; |
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class) |
|
||||||
public class DefaultKeyStoreWrapperProviderTest { |
|
||||||
|
|
||||||
@Mock private HardwareKeyStoreWrapperProvider hardwareKeyStoreWrapperProvider; |
|
||||||
@Mock private SoftwareKeyStoreWrapperProvider softwareKeyStoreWrapperProvider; |
|
||||||
@InjectMocks private DefaultKeyStoreWrapperProvider keyStoreWrapperProvider; |
|
||||||
|
|
||||||
private final Path keystorePath = Path.of("/keystore"); |
|
||||||
private final String keystorePassword = "pwd"; |
|
||||||
private final Path crlPath = Path.of("/crl"); |
|
||||||
|
|
||||||
@Test |
|
||||||
public void configWithTypePKCS11UsesHardwareKeyStoreProvider() { |
|
||||||
keyStoreWrapperProvider.apply( |
|
||||||
KeyStoreWrapper.KEYSTORE_TYPE_PKCS11, keystorePath, keystorePassword, crlPath); |
|
||||||
|
|
||||||
verify(hardwareKeyStoreWrapperProvider) |
|
||||||
.get(eq(keystorePassword), eq(keystorePath), eq(crlPath)); |
|
||||||
verifyNoInteractions(softwareKeyStoreWrapperProvider); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void configWithTypePKCS12UsesSoftwareKeyStoreProvider() { |
|
||||||
keyStoreWrapperProvider.apply( |
|
||||||
KeyStoreWrapper.KEYSTORE_TYPE_PKCS12, keystorePath, keystorePassword, crlPath); |
|
||||||
|
|
||||||
verify(softwareKeyStoreWrapperProvider) |
|
||||||
.get( |
|
||||||
eq(KeyStoreWrapper.KEYSTORE_TYPE_PKCS12), |
|
||||||
eq(keystorePath), |
|
||||||
eq(keystorePassword), |
|
||||||
eq(crlPath)); |
|
||||||
verifyNoInteractions(hardwareKeyStoreWrapperProvider); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void configWithTypeJKSUsesSoftwareKeyStoreProvider() { |
|
||||||
keyStoreWrapperProvider.apply( |
|
||||||
KeyStoreWrapper.KEYSTORE_TYPE_JKS, keystorePath, keystorePassword, crlPath); |
|
||||||
|
|
||||||
verify(softwareKeyStoreWrapperProvider) |
|
||||||
.get( |
|
||||||
eq(KeyStoreWrapper.KEYSTORE_TYPE_JKS), |
|
||||||
eq(keystorePath), |
|
||||||
eq(keystorePassword), |
|
||||||
eq(crlPath)); |
|
||||||
verifyNoInteractions(hardwareKeyStoreWrapperProvider); |
|
||||||
} |
|
||||||
} |
|
@ -1,75 +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.consensus.qbft.pki; |
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat; |
|
||||||
import static org.mockito.ArgumentMatchers.any; |
|
||||||
import static org.mockito.ArgumentMatchers.eq; |
|
||||||
import static org.mockito.ArgumentMatchers.isNull; |
|
||||||
import static org.mockito.Mockito.doReturn; |
|
||||||
import static org.mockito.Mockito.spy; |
|
||||||
import static org.mockito.Mockito.when; |
|
||||||
|
|
||||||
import org.hyperledger.besu.pki.config.PkiKeyStoreConfiguration; |
|
||||||
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper; |
|
||||||
|
|
||||||
import java.nio.file.Path; |
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test; |
|
||||||
import org.junit.jupiter.api.extension.ExtendWith; |
|
||||||
import org.mockito.Mock; |
|
||||||
import org.mockito.junit.jupiter.MockitoExtension; |
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class) |
|
||||||
public class PkiBlockCreationConfigurationProviderTest { |
|
||||||
|
|
||||||
@Mock KeyStoreWrapperProvider keyStoreWrapperProvider; |
|
||||||
@Mock KeyStoreWrapper keyStoreWrapper; |
|
||||||
@Mock KeyStoreWrapper trustStoreWrapper; |
|
||||||
|
|
||||||
@Test |
|
||||||
public void pkiBlockCreationConfigurationIsLoadedCorrectly() { |
|
||||||
when(keyStoreWrapperProvider.apply(any(), eq(Path.of("/tmp/keystore")), eq("pwd"), isNull())) |
|
||||||
.thenReturn(keyStoreWrapper); |
|
||||||
when(keyStoreWrapperProvider.apply( |
|
||||||
any(), eq(Path.of("/tmp/truststore")), eq("pwd"), eq(Path.of("/tmp/crl")))) |
|
||||||
.thenReturn(trustStoreWrapper); |
|
||||||
|
|
||||||
final PkiKeyStoreConfiguration pkiKeyStoreConfiguration = |
|
||||||
spy( |
|
||||||
new PkiKeyStoreConfiguration.Builder() |
|
||||||
.withKeyStorePath(Path.of("/tmp/keystore")) |
|
||||||
.withKeyStorePasswordPath(Path.of("/tmp/password")) |
|
||||||
.withTrustStorePath(Path.of("/tmp/truststore")) |
|
||||||
.withTrustStorePasswordPath(Path.of("/tmp/password")) |
|
||||||
.withCertificateAlias("anAlias") |
|
||||||
.withCrlFilePath(Path.of("/tmp/crl")) |
|
||||||
.build()); |
|
||||||
doReturn("pwd").when(pkiKeyStoreConfiguration).getKeyStorePassword(); |
|
||||||
doReturn("pwd").when(pkiKeyStoreConfiguration).getTrustStorePassword(); |
|
||||||
|
|
||||||
final PkiBlockCreationConfigurationProvider pkiBlockCreationConfigProvider = |
|
||||||
new PkiBlockCreationConfigurationProvider(keyStoreWrapperProvider); |
|
||||||
|
|
||||||
final PkiBlockCreationConfiguration pkiBlockCreationConfiguration = |
|
||||||
pkiBlockCreationConfigProvider.load(pkiKeyStoreConfiguration); |
|
||||||
|
|
||||||
assertThat(pkiBlockCreationConfiguration).isNotNull(); |
|
||||||
assertThat(pkiBlockCreationConfiguration.getKeyStore()).isNotNull(); |
|
||||||
assertThat(pkiBlockCreationConfiguration.getTrustStore()).isNotNull(); |
|
||||||
assertThat(pkiBlockCreationConfiguration.getCertificateAlias()).isEqualTo("anAlias"); |
|
||||||
} |
|
||||||
} |
|
@ -1,85 +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.consensus.qbft.pki; |
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat; |
|
||||||
import static org.mockito.ArgumentMatchers.any; |
|
||||||
import static org.mockito.Mockito.spy; |
|
||||||
import static org.mockito.Mockito.times; |
|
||||||
import static org.mockito.Mockito.verify; |
|
||||||
|
|
||||||
import org.hyperledger.besu.consensus.common.bft.BftBlockHashing; |
|
||||||
import org.hyperledger.besu.consensus.common.bft.BftExtraData; |
|
||||||
import org.hyperledger.besu.consensus.common.bft.BftExtraDataFixture; |
|
||||||
import org.hyperledger.besu.datatypes.Hash; |
|
||||||
import org.hyperledger.besu.ethereum.core.BlockHeader; |
|
||||||
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; |
|
||||||
|
|
||||||
import org.apache.tuweni.bytes.Bytes; |
|
||||||
import org.junit.jupiter.api.BeforeEach; |
|
||||||
import org.junit.jupiter.api.Test; |
|
||||||
|
|
||||||
public class PkiQbftBlockHashingTest { |
|
||||||
|
|
||||||
private PkiQbftExtraDataCodec pkiExtraDataCodec = new PkiQbftExtraDataCodec(); |
|
||||||
private PkiQbftBlockHashing pkiQbftBlockHashing; |
|
||||||
|
|
||||||
@BeforeEach |
|
||||||
public void before() { |
|
||||||
pkiExtraDataCodec = spy(new PkiQbftExtraDataCodec()); |
|
||||||
pkiQbftBlockHashing = new PkiQbftBlockHashing(pkiExtraDataCodec); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void blockHashingUsesCorrectEncodingWithoutCmsMethodInCodec() { |
|
||||||
final PkiQbftExtraData pkiQbftExtraData = createPkiQbftExtraData(); |
|
||||||
final BlockHeader headerWithExtraData = |
|
||||||
new BlockHeaderTestFixture() |
|
||||||
.number(1L) |
|
||||||
.extraData(pkiExtraDataCodec.encode(pkiQbftExtraData)) |
|
||||||
.buildHeader(); |
|
||||||
|
|
||||||
// Expected hash using the extraData encoded by the encodeWithoutCms method of the codec
|
|
||||||
final Hash expectedHash = |
|
||||||
Hash.hash( |
|
||||||
BftBlockHashing.serializeHeader( |
|
||||||
headerWithExtraData, |
|
||||||
() -> pkiExtraDataCodec.encodeWithoutCms(pkiQbftExtraData), |
|
||||||
pkiExtraDataCodec)); |
|
||||||
|
|
||||||
final Hash hash = |
|
||||||
pkiQbftBlockHashing.calculateHashOfBftBlockForCmsSignature(headerWithExtraData); |
|
||||||
|
|
||||||
assertThat(hash).isEqualTo(expectedHash); |
|
||||||
|
|
||||||
/* |
|
||||||
Verify that the encodeWithoutCms method was called twice, once when calculating the |
|
||||||
expected hash and a second time as part of the hash calculation on |
|
||||||
calculateHashOfBftBlockForCmsSignature |
|
||||||
*/ |
|
||||||
verify(pkiExtraDataCodec, times(2)).encodeWithoutCms(any(PkiQbftExtraData.class)); |
|
||||||
} |
|
||||||
|
|
||||||
private PkiQbftExtraData createPkiQbftExtraData() { |
|
||||||
final BlockHeader blockHeader = new BlockHeaderTestFixture().buildHeader(); |
|
||||||
final BftExtraData extraData = |
|
||||||
BftExtraDataFixture.createExtraData(blockHeader, pkiExtraDataCodec); |
|
||||||
return new PkiQbftExtraData(extraData, Bytes.random(32)); |
|
||||||
} |
|
||||||
} |
|
@ -1,243 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2020 ConsenSys AG. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
|
||||||
* the License. You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
|
||||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
|
||||||
* specific language governing permissions and limitations under the License. |
|
||||||
* |
|
||||||
* SPDX-License-Identifier: Apache-2.0 |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.hyperledger.besu.consensus.qbft.pki; |
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat; |
|
||||||
import static org.hyperledger.besu.consensus.qbft.QbftExtraDataCodecTestUtils.createNonEmptyVanityData; |
|
||||||
|
|
||||||
import org.hyperledger.besu.consensus.common.bft.BftExtraData; |
|
||||||
import org.hyperledger.besu.consensus.common.bft.Vote; |
|
||||||
import org.hyperledger.besu.crypto.SECPSignature; |
|
||||||
import org.hyperledger.besu.crypto.SignatureAlgorithm; |
|
||||||
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; |
|
||||||
import org.hyperledger.besu.datatypes.Address; |
|
||||||
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; |
|
||||||
|
|
||||||
import java.math.BigInteger; |
|
||||||
import java.util.Arrays; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Optional; |
|
||||||
import java.util.Random; |
|
||||||
import java.util.function.Supplier; |
|
||||||
|
|
||||||
import com.google.common.base.Suppliers; |
|
||||||
import org.apache.tuweni.bytes.Bytes; |
|
||||||
import org.junit.jupiter.api.Test; |
|
||||||
|
|
||||||
public class PkiQbftExtraDataCodecTest { |
|
||||||
|
|
||||||
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM = |
|
||||||
Suppliers.memoize(SignatureAlgorithmFactory::getInstance); |
|
||||||
|
|
||||||
// Arbitrary bytes representing a non-empty CMS
|
|
||||||
private final Bytes cms = Bytes.fromHexString("0x01"); |
|
||||||
|
|
||||||
private final String RAW_EXCLUDE_COMMIT_SEALS_AND_ROUND_NUMBER_ENCODED_STRING = |
|
||||||
"0xf867a00102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20ea940000000000000000" |
|
||||||
+ "000000000000000000000001940000000000000000000000000000000000000002d7940000000000000000" |
|
||||||
+ "00000000000000000000000181ff80c001"; |
|
||||||
|
|
||||||
private final String RAW_EXCLUDE_COMMIT_SEALS_ENCODED_STRING = |
|
||||||
"0xf86aa00102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20ea940000000000000000" |
|
||||||
+ "000000000000000000000001940000000000000000000000000000000000000002d7940000000000000000" |
|
||||||
+ "00000000000000000000000181ff83fedcbac001"; |
|
||||||
|
|
||||||
private final String RAW_ALL_ENCODED_STRING = |
|
||||||
"0xf8f1a00102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20ea940000000000000000" |
|
||||||
+ "000000000000000000000001940000000000000000000000000000000000000002d7940000000000000000" |
|
||||||
+ "00000000000000000000000181ff83fedcbaf886b841000000000000000000000000000000000000000000" |
|
||||||
+ "0000000000000000000001000000000000000000000000000000000000000000000000000000000000000a" |
|
||||||
+ "00b841000000000000000000000000000000000000000000000000000000000000000a0000000000000000" |
|
||||||
+ "0000000000000000000000000000000000000000000000010001"; |
|
||||||
|
|
||||||
private final String RAW_QBFT_EXTRA_DATA = |
|
||||||
"0xf8f0a00102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20ea940000000000000000" |
|
||||||
+ "000000000000000000000001940000000000000000000000000000000000000002d7940000000000000000" |
|
||||||
+ "00000000000000000000000181ff83fedcbaf886b841000000000000000000000000000000000000000000" |
|
||||||
+ "0000000000000000000001000000000000000000000000000000000000000000000000000000000000000a" |
|
||||||
+ "00b841000000000000000000000000000000000000000000000000000000000000000a0000000000000000" |
|
||||||
+ "00000000000000000000000000000000000000000000000100"; |
|
||||||
|
|
||||||
private final PkiQbftExtraDataCodec bftExtraDataCodec = new PkiQbftExtraDataCodec(); |
|
||||||
|
|
||||||
@Test |
|
||||||
public void fullyPopulatedDataProducesCorrectlyFormedExtraDataObject() { |
|
||||||
final List<Address> validators = |
|
||||||
Arrays.asList(Address.fromHexString("1"), Address.fromHexString("2")); |
|
||||||
final int round = 0x00FEDCBA; |
|
||||||
final List<SECPSignature> committerSeals = |
|
||||||
Arrays.asList( |
|
||||||
SIGNATURE_ALGORITHM.get().createSignature(BigInteger.ONE, BigInteger.TEN, (byte) 0), |
|
||||||
SIGNATURE_ALGORITHM.get().createSignature(BigInteger.TEN, BigInteger.ONE, (byte) 0)); |
|
||||||
|
|
||||||
// Create randomised vanity data.
|
|
||||||
final byte[] vanity_bytes = createNonEmptyVanityData(); |
|
||||||
new Random().nextBytes(vanity_bytes); |
|
||||||
final Bytes vanity_data = Bytes.wrap(vanity_bytes); |
|
||||||
|
|
||||||
final BytesValueRLPOutput encoder = new BytesValueRLPOutput(); |
|
||||||
encoder.startList(); // start extra data list
|
|
||||||
// vanity data
|
|
||||||
encoder.writeBytes(vanity_data); |
|
||||||
// validators
|
|
||||||
encoder.writeList(validators, (validator, rlp) -> rlp.writeBytes(validator)); |
|
||||||
// votes
|
|
||||||
encoder.startList(); |
|
||||||
encoder.writeBytes(Address.fromHexString("1")); |
|
||||||
encoder.writeByte(Vote.ADD_BYTE_VALUE); |
|
||||||
encoder.endList(); |
|
||||||
// rounds
|
|
||||||
encoder.writeIntScalar(round); |
|
||||||
// committer seals
|
|
||||||
encoder.writeList(committerSeals, (committer, rlp) -> rlp.writeBytes(committer.encodedBytes())); |
|
||||||
// cms
|
|
||||||
encoder.writeBytes(cms); |
|
||||||
encoder.endList(); // end extra data list
|
|
||||||
|
|
||||||
final Bytes bufferToInject = encoder.encoded(); |
|
||||||
|
|
||||||
final PkiQbftExtraData extraData = |
|
||||||
(PkiQbftExtraData) bftExtraDataCodec.decodeRaw(bufferToInject); |
|
||||||
|
|
||||||
assertThat(extraData.getVanityData()).isEqualTo(vanity_data); |
|
||||||
assertThat(extraData.getRound()).isEqualTo(round); |
|
||||||
assertThat(extraData.getSeals()).isEqualTo(committerSeals); |
|
||||||
assertThat(extraData.getValidators()).isEqualTo(validators); |
|
||||||
assertThat(extraData.getCms()).isEqualTo(cms); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void decodingQbftExtraDataDelegatesToQbftCodec() { |
|
||||||
final List<Address> validators = |
|
||||||
Arrays.asList(Address.fromHexString("1"), Address.fromHexString("2")); |
|
||||||
final int round = 0x00FEDCBA; |
|
||||||
final List<SECPSignature> committerSeals = |
|
||||||
Arrays.asList( |
|
||||||
SIGNATURE_ALGORITHM.get().createSignature(BigInteger.ONE, BigInteger.TEN, (byte) 0), |
|
||||||
SIGNATURE_ALGORITHM.get().createSignature(BigInteger.TEN, BigInteger.ONE, (byte) 0)); |
|
||||||
|
|
||||||
// Create randomised vanity data.
|
|
||||||
final byte[] vanity_bytes = createNonEmptyVanityData(); |
|
||||||
new Random().nextBytes(vanity_bytes); |
|
||||||
final Bytes vanity_data = Bytes.wrap(vanity_bytes); |
|
||||||
|
|
||||||
final BytesValueRLPOutput encoder = new BytesValueRLPOutput(); |
|
||||||
encoder.startList(); // start extra data list
|
|
||||||
// vanity data
|
|
||||||
encoder.writeBytes(vanity_data); |
|
||||||
// validators
|
|
||||||
encoder.writeList(validators, (validator, rlp) -> rlp.writeBytes(validator)); |
|
||||||
// votes
|
|
||||||
encoder.startList(); |
|
||||||
encoder.writeBytes(Address.fromHexString("1")); |
|
||||||
encoder.writeByte(Vote.ADD_BYTE_VALUE); |
|
||||||
encoder.endList(); |
|
||||||
// rounds
|
|
||||||
encoder.writeIntScalar(round); |
|
||||||
// committer seals
|
|
||||||
encoder.writeList(committerSeals, (committer, rlp) -> rlp.writeBytes(committer.encodedBytes())); |
|
||||||
// Not including the CMS in the list (to generate a non-pki QBFT extra data)
|
|
||||||
encoder.endList(); // end extra data list
|
|
||||||
|
|
||||||
final Bytes bufferToInject = encoder.encoded(); |
|
||||||
|
|
||||||
final PkiQbftExtraData extraData = |
|
||||||
(PkiQbftExtraData) bftExtraDataCodec.decodeRaw(bufferToInject); |
|
||||||
|
|
||||||
assertThat(extraData.getVanityData()).isEqualTo(vanity_data); |
|
||||||
assertThat(extraData.getRound()).isEqualTo(round); |
|
||||||
assertThat(extraData.getSeals()).isEqualTo(committerSeals); |
|
||||||
assertThat(extraData.getValidators()).isEqualTo(validators); |
|
||||||
assertThat(extraData.getCms()).isEqualTo(Bytes.EMPTY); |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
When encoding for blockchain, we ignore commit seals and round number, but we include the CMS |
|
||||||
*/ |
|
||||||
@Test |
|
||||||
public void encodingForBlockchainShouldIncludeCms() { |
|
||||||
final Bytes expectedRawDecoding = |
|
||||||
Bytes.fromHexString(RAW_EXCLUDE_COMMIT_SEALS_AND_ROUND_NUMBER_ENCODED_STRING); |
|
||||||
final Bytes encoded = |
|
||||||
bftExtraDataCodec.encodeWithoutCommitSealsAndRoundNumber(getDecodedExtraData(cms)); |
|
||||||
|
|
||||||
assertThat(encoded).isEqualTo(expectedRawDecoding); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void encodingWithoutCommitSealsShouldIncludeCms() { |
|
||||||
final Bytes expectedRawDecoding = Bytes.fromHexString(RAW_EXCLUDE_COMMIT_SEALS_ENCODED_STRING); |
|
||||||
final Bytes encoded = bftExtraDataCodec.encodeWithoutCommitSeals(getDecodedExtraData(cms)); |
|
||||||
|
|
||||||
assertThat(encoded).isEqualTo(expectedRawDecoding); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void encodingWithAllShouldIncludeCms() { |
|
||||||
final Bytes expectedRawDecoding = Bytes.fromHexString(RAW_ALL_ENCODED_STRING); |
|
||||||
final Bytes encoded = bftExtraDataCodec.encode(getDecodedExtraData(cms)); |
|
||||||
|
|
||||||
assertThat(encoded).isEqualTo(expectedRawDecoding); |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
When encoding for proposal, we include commit seals and round number, but we ignore the CMS |
|
||||||
*/ |
|
||||||
@Test |
|
||||||
public void encodingForCreatingCmsProposal() { |
|
||||||
final Bytes expectedRawDecoding = Bytes.fromHexString(RAW_QBFT_EXTRA_DATA); |
|
||||||
final Bytes encoded = bftExtraDataCodec.encodeWithoutCms(getDecodedExtraData(cms)); |
|
||||||
|
|
||||||
assertThat(encoded).isEqualTo(expectedRawDecoding); |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
When encoding non-pki extra data, we delegate to the regular QBFT encoder |
|
||||||
*/ |
|
||||||
@Test |
|
||||||
public void encodingQbftExtraData() { |
|
||||||
final Bytes expectedRawDecoding = Bytes.fromHexString(RAW_QBFT_EXTRA_DATA); |
|
||||||
final PkiQbftExtraData pkiBftExtraData = getDecodedExtraData(cms); |
|
||||||
final BftExtraData bftExtraData = |
|
||||||
new BftExtraData( |
|
||||||
pkiBftExtraData.getVanityData(), |
|
||||||
pkiBftExtraData.getSeals(), |
|
||||||
pkiBftExtraData.getVote(), |
|
||||||
pkiBftExtraData.getRound(), |
|
||||||
pkiBftExtraData.getValidators()); |
|
||||||
|
|
||||||
final Bytes encoded = bftExtraDataCodec.encode(bftExtraData); |
|
||||||
|
|
||||||
assertThat(encoded).isEqualTo(expectedRawDecoding); |
|
||||||
} |
|
||||||
|
|
||||||
private static PkiQbftExtraData getDecodedExtraData(final Bytes cms) { |
|
||||||
final List<Address> validators = |
|
||||||
Arrays.asList(Address.fromHexString("1"), Address.fromHexString("2")); |
|
||||||
final Optional<Vote> vote = Optional.of(Vote.authVote(Address.fromHexString("1"))); |
|
||||||
final int round = 0x00FEDCBA; |
|
||||||
final List<SECPSignature> committerSeals = |
|
||||||
Arrays.asList( |
|
||||||
SIGNATURE_ALGORITHM.get().createSignature(BigInteger.ONE, BigInteger.TEN, (byte) 0), |
|
||||||
SIGNATURE_ALGORITHM.get().createSignature(BigInteger.TEN, BigInteger.ONE, (byte) 0)); |
|
||||||
|
|
||||||
// Create a byte buffer with no data.
|
|
||||||
final byte[] vanity_bytes = createNonEmptyVanityData(); |
|
||||||
final Bytes vanity_data = Bytes.wrap(vanity_bytes); |
|
||||||
|
|
||||||
return new PkiQbftExtraData(vanity_data, committerSeals, vote, round, validators, cms); |
|
||||||
} |
|
||||||
} |
|
@ -1,202 +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 static org.hyperledger.besu.pki.util.TestCertificateUtils.Algorithm.EC; |
|
||||||
import static org.hyperledger.besu.pki.util.TestCertificateUtils.Algorithm.RSA; |
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse; |
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue; |
|
||||||
|
|
||||||
import org.hyperledger.besu.pki.util.TestCertificateUtils.Algorithm; |
|
||||||
|
|
||||||
import java.security.PrivateKey; |
|
||||||
import java.security.PublicKey; |
|
||||||
import java.security.cert.X509Certificate; |
|
||||||
|
|
||||||
import org.apache.tuweni.bytes.Bytes; |
|
||||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; |
|
||||||
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.operator.ContentSigner; |
|
||||||
import org.bouncycastle.operator.DigestCalculatorProvider; |
|
||||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; |
|
||||||
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; |
|
||||||
import org.junit.jupiter.params.ParameterizedTest; |
|
||||||
import org.junit.jupiter.params.provider.EnumSource; |
|
||||||
|
|
||||||
public class CmsCreationAndValidationTest { |
|
||||||
|
|
||||||
private static final CmsTestKeystores rsaTestKeystores = new CmsTestKeystores(RSA); |
|
||||||
private static final CmsTestKeystores ecTestKeystores = new CmsTestKeystores(EC); |
|
||||||
|
|
||||||
private CmsTestKeystores getCmsTestKeystores(final Algorithm algorithm) { |
|
||||||
return switch (algorithm) { |
|
||||||
case RSA -> rsaTestKeystores; |
|
||||||
case EC -> ecTestKeystores; |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@EnumSource(value = Algorithm.class) |
|
||||||
public void cmsValidationWithEmptyCmsMessage(final Algorithm algorithm) { |
|
||||||
final Bytes data = Bytes.random(32); |
|
||||||
|
|
||||||
assertFalse(getCmsTestKeystores(algorithm).getCmsValidator().validate(Bytes.EMPTY, data)); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@EnumSource(value = Algorithm.class) |
|
||||||
public void cmsValidationWithTrustedSelfSignedCertificate(final Algorithm algorithm) { |
|
||||||
final CmsCreator cmsCreator = |
|
||||||
new CmsCreator(getCmsTestKeystores(algorithm).getKeystoreWrapper(), "trusted_selfsigned"); |
|
||||||
final Bytes data = Bytes.random(32); |
|
||||||
|
|
||||||
final Bytes cms = cmsCreator.create(data); |
|
||||||
|
|
||||||
assertTrue(getCmsTestKeystores(algorithm).getCmsValidator().validate(cms, data)); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@EnumSource(value = Algorithm.class) |
|
||||||
public void cmsValidationWithUntrustedSelfSignedCertificate(final Algorithm algorithm) { |
|
||||||
final CmsCreator cmsCreator = |
|
||||||
new CmsCreator(getCmsTestKeystores(algorithm).getKeystoreWrapper(), "untrusted_selfsigned"); |
|
||||||
final Bytes data = Bytes.random(32); |
|
||||||
|
|
||||||
final Bytes cms = cmsCreator.create(data); |
|
||||||
|
|
||||||
assertFalse(getCmsTestKeystores(algorithm).getCmsValidator().validate(cms, data)); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@EnumSource(value = Algorithm.class) |
|
||||||
public void cmsValidationWithTrustedChain(final Algorithm algorithm) { |
|
||||||
final CmsCreator cmsCreator = |
|
||||||
new CmsCreator(getCmsTestKeystores(algorithm).getKeystoreWrapper(), "trusted"); |
|
||||||
final Bytes data = Bytes.random(32); |
|
||||||
|
|
||||||
final Bytes cms = cmsCreator.create(data); |
|
||||||
|
|
||||||
assertTrue(getCmsTestKeystores(algorithm).getCmsValidator().validate(cms, data)); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@EnumSource(value = Algorithm.class) |
|
||||||
public void cmsValidationWithUntrustedChain(final Algorithm algorithm) { |
|
||||||
final CmsCreator cmsCreator = |
|
||||||
new CmsCreator(getCmsTestKeystores(algorithm).getKeystoreWrapper(), "untrusted"); |
|
||||||
final Bytes data = Bytes.random(32); |
|
||||||
|
|
||||||
final Bytes cms = cmsCreator.create(data); |
|
||||||
|
|
||||||
assertFalse(getCmsTestKeystores(algorithm).getCmsValidator().validate(cms, data)); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@EnumSource(value = Algorithm.class) |
|
||||||
public void cmsValidationWithExpiredCertificate(final Algorithm algorithm) { |
|
||||||
final CmsCreator cmsCreator = |
|
||||||
new CmsCreator(getCmsTestKeystores(algorithm).getKeystoreWrapper(), "expired"); |
|
||||||
final Bytes data = Bytes.random(32); |
|
||||||
|
|
||||||
final Bytes cms = cmsCreator.create(data); |
|
||||||
|
|
||||||
assertFalse(getCmsTestKeystores(algorithm).getCmsValidator().validate(cms, data)); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@EnumSource(value = Algorithm.class) |
|
||||||
public void cmsValidationWithRevokedCertificate(final Algorithm algorithm) { |
|
||||||
final CmsCreator cmsCreator = |
|
||||||
new CmsCreator(getCmsTestKeystores(algorithm).getKeystoreWrapper(), "revoked"); |
|
||||||
final Bytes data = Bytes.random(32); |
|
||||||
|
|
||||||
final Bytes cms = cmsCreator.create(data); |
|
||||||
|
|
||||||
assertFalse(getCmsTestKeystores(algorithm).getCmsValidator().validate(cms, data)); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@EnumSource(value = Algorithm.class) |
|
||||||
public void cmsValidationWithoutCRLConfigDisablesCRLCheck(final Algorithm algorithm) { |
|
||||||
final CmsCreator cmsCreator = |
|
||||||
new CmsCreator(getCmsTestKeystores(algorithm).getKeystoreWrapper(), "revoked"); |
|
||||||
final Bytes data = Bytes.random(32); |
|
||||||
|
|
||||||
final Bytes cms = cmsCreator.create(data); |
|
||||||
|
|
||||||
CmsValidator cmsValidator = getCmsTestKeystores(algorithm).getCmsValidatorWithoutCrl(); |
|
||||||
|
|
||||||
// Because we don't have a CRL CertStore, revocation is not checked
|
|
||||||
assertTrue(cmsValidator.validate(cms, data)); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@EnumSource(value = Algorithm.class) |
|
||||||
public void cmsValidationWithWrongSignedData(final Algorithm algorithm) { |
|
||||||
final CmsCreator cmsCreator = |
|
||||||
new CmsCreator(getCmsTestKeystores(algorithm).getKeystoreWrapper(), "trusted"); |
|
||||||
final Bytes otherData = Bytes.random(32); |
|
||||||
final Bytes cms = cmsCreator.create(otherData); |
|
||||||
|
|
||||||
final Bytes expectedData = Bytes.random(32); |
|
||||||
assertFalse(getCmsTestKeystores(algorithm).getCmsValidator().validate(cms, expectedData)); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@EnumSource(value = Algorithm.class) |
|
||||||
public void cmsValidationWithInvalidSignature(final Algorithm algorithm) throws Exception { |
|
||||||
// Create a CMS message signed with a certificate, but create SignerInfo using another
|
|
||||||
// certificate to trigger the signature verification to fail.
|
|
||||||
|
|
||||||
final PrivateKey privateKey = |
|
||||||
getCmsTestKeystores(algorithm).getKeystoreWrapper().getPrivateKey("trusted"); |
|
||||||
final PublicKey publicKey = |
|
||||||
getCmsTestKeystores(algorithm).getKeystoreWrapper().getPublicKey("trusted"); |
|
||||||
final X509Certificate signerCertificate = |
|
||||||
(X509Certificate) |
|
||||||
getCmsTestKeystores(algorithm).getKeystoreWrapper().getCertificate("trusted"); |
|
||||||
final X509Certificate otherCertificate = |
|
||||||
(X509Certificate) |
|
||||||
getCmsTestKeystores(algorithm) |
|
||||||
.getKeystoreWrapper() |
|
||||||
.getCertificate("trusted_selfsigned"); |
|
||||||
|
|
||||||
final ContentSigner contentSigner = |
|
||||||
new JcaContentSignerBuilder(CmsCreator.getPreferredSignatureAlgorithm(publicKey)) |
|
||||||
.build(privateKey); |
|
||||||
|
|
||||||
final CMSSignedDataGenerator cmsGenerator = new CMSSignedDataGenerator(); |
|
||||||
cmsGenerator.addCertificate(new JcaX509CertificateHolder(signerCertificate)); |
|
||||||
cmsGenerator.addCertificate(new JcaX509CertificateHolder(otherCertificate)); |
|
||||||
|
|
||||||
final DigestCalculatorProvider digestCalculatorProvider = |
|
||||||
new JcaDigestCalculatorProviderBuilder().setProvider("BC").build(); |
|
||||||
cmsGenerator.addSignerInfoGenerator( |
|
||||||
new JcaSignerInfoGeneratorBuilder(digestCalculatorProvider) |
|
||||||
.build(contentSigner, otherCertificate)); |
|
||||||
|
|
||||||
final Bytes expectedData = Bytes.random(32); |
|
||||||
final CMSTypedData cmsData = new CMSProcessableByteArray(expectedData.toArray()); |
|
||||||
final CMSSignedData cmsSignedData = cmsGenerator.generate(cmsData, true); |
|
||||||
final Bytes cmsBytes = Bytes.wrap(cmsSignedData.getEncoded()); |
|
||||||
|
|
||||||
assertFalse(getCmsTestKeystores(algorithm).getCmsValidator().validate(cmsBytes, expectedData)); |
|
||||||
} |
|
||||||
} |
|
@ -1,243 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright Hyperledger Besu Contributors. |
|
||||||
* |
|
||||||
* 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 static org.hyperledger.besu.pki.util.TestCertificateUtils.createCRL; |
|
||||||
import static org.hyperledger.besu.pki.util.TestCertificateUtils.createKeyPair; |
|
||||||
import static org.hyperledger.besu.pki.util.TestCertificateUtils.createSelfSignedCertificate; |
|
||||||
import static org.hyperledger.besu.pki.util.TestCertificateUtils.issueCertificate; |
|
||||||
|
|
||||||
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper; |
|
||||||
import org.hyperledger.besu.pki.keystore.SoftwareKeyStoreWrapper; |
|
||||||
import org.hyperledger.besu.pki.util.TestCertificateUtils.Algorithm; |
|
||||||
|
|
||||||
import java.security.KeyPair; |
|
||||||
import java.security.KeyStore; |
|
||||||
import java.security.cert.Certificate; |
|
||||||
import java.security.cert.X509CRL; |
|
||||||
import java.security.cert.X509Certificate; |
|
||||||
import java.time.Instant; |
|
||||||
import java.time.temporal.ChronoUnit; |
|
||||||
import java.util.Collections; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Set; |
|
||||||
|
|
||||||
public class CmsTestKeystores { |
|
||||||
private KeyStore keystore; |
|
||||||
private KeyStore truststore; |
|
||||||
private List<X509CRL> CRLs; |
|
||||||
|
|
||||||
private KeyStoreWrapper keystoreWrapper; |
|
||||||
private KeyStoreWrapper truststoreWrapper; |
|
||||||
private KeyStoreWrapper truststoreWrapperWithoutCrl; |
|
||||||
private CmsValidator cmsValidator; |
|
||||||
private CmsValidator cmsValidatorWithoutCrl; |
|
||||||
|
|
||||||
public CmsTestKeystores(final Algorithm algorithm) { |
|
||||||
try { |
|
||||||
init(algorithm); |
|
||||||
} catch (Exception e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void init(final Algorithm algorithm) throws Exception { |
|
||||||
final Instant notBefore = Instant.now().minus(1, ChronoUnit.DAYS); |
|
||||||
final Instant notAfter = Instant.now().plus(1, ChronoUnit.DAYS); |
|
||||||
|
|
||||||
/* |
|
||||||
Create self-signed certificate |
|
||||||
*/ |
|
||||||
final KeyPair selfsignedKeyPair = createKeyPair(algorithm); |
|
||||||
final X509Certificate selfsignedCertificate = |
|
||||||
createSelfSignedCertificate("selfsigned", notBefore, notAfter, selfsignedKeyPair); |
|
||||||
|
|
||||||
/* |
|
||||||
Create trusted chain (ca -> interca -> partneraca -> partneravalidator) |
|
||||||
*/ |
|
||||||
final KeyPair caKeyPair = createKeyPair(algorithm); |
|
||||||
final X509Certificate caCertificate = |
|
||||||
createSelfSignedCertificate("ca", notBefore, notAfter, caKeyPair); |
|
||||||
|
|
||||||
final KeyPair interCAKeyPair = createKeyPair(algorithm); |
|
||||||
final X509Certificate interCACertificate = |
|
||||||
issueCertificate( |
|
||||||
caCertificate, caKeyPair, "interca", notBefore, notAfter, interCAKeyPair, true); |
|
||||||
|
|
||||||
final KeyPair partnerACAPair = createKeyPair(algorithm); |
|
||||||
final X509Certificate partnerACACertificate = |
|
||||||
issueCertificate( |
|
||||||
interCACertificate, |
|
||||||
interCAKeyPair, |
|
||||||
"partneraca", |
|
||||||
notBefore, |
|
||||||
notAfter, |
|
||||||
partnerACAPair, |
|
||||||
true); |
|
||||||
|
|
||||||
final KeyPair parterAValidatorKeyPair = createKeyPair(algorithm); |
|
||||||
final X509Certificate partnerAValidatorCertificate = |
|
||||||
issueCertificate( |
|
||||||
partnerACACertificate, |
|
||||||
partnerACAPair, |
|
||||||
"partneravalidator", |
|
||||||
notBefore, |
|
||||||
notAfter, |
|
||||||
parterAValidatorKeyPair, |
|
||||||
false); |
|
||||||
|
|
||||||
/* |
|
||||||
Create expired certificate |
|
||||||
*/ |
|
||||||
final KeyPair expiredKeyPair = createKeyPair(algorithm); |
|
||||||
final X509Certificate expiredCertificate = |
|
||||||
issueCertificate( |
|
||||||
caCertificate, |
|
||||||
caKeyPair, |
|
||||||
"expired", |
|
||||||
notBefore, |
|
||||||
notBefore.plus(1, ChronoUnit.SECONDS), |
|
||||||
expiredKeyPair, |
|
||||||
true); |
|
||||||
|
|
||||||
/* |
|
||||||
Create revoked and revoked certificates |
|
||||||
*/ |
|
||||||
final KeyPair revokedKeyPair = createKeyPair(algorithm); |
|
||||||
final X509Certificate revokedCertificate = |
|
||||||
issueCertificate( |
|
||||||
caCertificate, caKeyPair, "revoked", notBefore, notAfter, revokedKeyPair, true); |
|
||||||
|
|
||||||
/* |
|
||||||
Create untrusted chain (untrusted_selfsigned -> unstrusted_partner) |
|
||||||
*/ |
|
||||||
final KeyPair untrustedSelfSignedKeyPair = createKeyPair(algorithm); |
|
||||||
final X509Certificate untrustedSelfsignedCertificate = |
|
||||||
createSelfSignedCertificate( |
|
||||||
"untrusted_selfsigned", notBefore, notAfter, untrustedSelfSignedKeyPair); |
|
||||||
|
|
||||||
final KeyPair untrustedIntermediateKeyPair = createKeyPair(algorithm); |
|
||||||
final X509Certificate untrustedIntermediateCertificate = |
|
||||||
issueCertificate( |
|
||||||
untrustedSelfsignedCertificate, |
|
||||||
untrustedSelfSignedKeyPair, |
|
||||||
"unstrusted_partner", |
|
||||||
notBefore, |
|
||||||
notAfter, |
|
||||||
untrustedIntermediateKeyPair, |
|
||||||
true); |
|
||||||
|
|
||||||
/* |
|
||||||
Create truststore wrapper with 3 trusted certificates: 'ca', 'interca' and 'selfsigned' |
|
||||||
*/ |
|
||||||
truststore = KeyStore.getInstance("PKCS12"); |
|
||||||
truststore.load(null, null); |
|
||||||
|
|
||||||
truststore.setCertificateEntry("ca", caCertificate); |
|
||||||
truststore.setCertificateEntry("interca", interCACertificate); |
|
||||||
truststore.setCertificateEntry("selfsigned", selfsignedCertificate); |
|
||||||
|
|
||||||
/* |
|
||||||
Create keystore with certificates used in tests |
|
||||||
*/ |
|
||||||
keystore = KeyStore.getInstance("PKCS12"); |
|
||||||
keystore.load(null, null); |
|
||||||
|
|
||||||
keystore.setKeyEntry( |
|
||||||
"trusted_selfsigned", |
|
||||||
selfsignedKeyPair.getPrivate(), |
|
||||||
"".toCharArray(), |
|
||||||
new Certificate[] {selfsignedCertificate}); |
|
||||||
keystore.setKeyEntry( |
|
||||||
"untrusted_selfsigned", |
|
||||||
untrustedSelfSignedKeyPair.getPrivate(), |
|
||||||
"".toCharArray(), |
|
||||||
new Certificate[] {untrustedSelfsignedCertificate}); |
|
||||||
keystore.setKeyEntry( |
|
||||||
"expired", |
|
||||||
expiredKeyPair.getPrivate(), |
|
||||||
"".toCharArray(), |
|
||||||
new Certificate[] {expiredCertificate}); |
|
||||||
keystore.setKeyEntry( |
|
||||||
"revoked", |
|
||||||
revokedKeyPair.getPrivate(), |
|
||||||
"".toCharArray(), |
|
||||||
new Certificate[] {revokedCertificate}); |
|
||||||
keystore.setKeyEntry( |
|
||||||
"trusted", |
|
||||||
parterAValidatorKeyPair.getPrivate(), |
|
||||||
"".toCharArray(), |
|
||||||
new Certificate[] {partnerAValidatorCertificate, partnerACACertificate}); |
|
||||||
keystore.setKeyEntry( |
|
||||||
"untrusted", |
|
||||||
untrustedIntermediateKeyPair.getPrivate(), |
|
||||||
"".toCharArray(), |
|
||||||
new Certificate[] {untrustedIntermediateCertificate, untrustedSelfsignedCertificate}); |
|
||||||
|
|
||||||
/* |
|
||||||
Create CRLs for all CA certificates (mostly empty, only ca has one revoked certificate) |
|
||||||
*/ |
|
||||||
final X509CRL caCRL = createCRL(caCertificate, caKeyPair, Set.of(revokedCertificate)); |
|
||||||
final X509CRL intercaCRL = |
|
||||||
createCRL(interCACertificate, interCAKeyPair, Collections.emptyList()); |
|
||||||
final X509CRL partnerACACRL = |
|
||||||
createCRL(partnerACACertificate, partnerACAPair, Collections.emptyList()); |
|
||||||
final X509CRL selfsignedCRL = |
|
||||||
createCRL(selfsignedCertificate, selfsignedKeyPair, Collections.emptyList()); |
|
||||||
CRLs = List.of(caCRL, intercaCRL, partnerACACRL, selfsignedCRL); |
|
||||||
|
|
||||||
keystoreWrapper = new SoftwareKeyStoreWrapper(null, keystore, ""); |
|
||||||
|
|
||||||
truststoreWrapper = new SoftwareKeyStoreWrapper(CRLs, truststore, ""); |
|
||||||
|
|
||||||
truststoreWrapperWithoutCrl = new SoftwareKeyStoreWrapper(null, truststore, ""); |
|
||||||
|
|
||||||
cmsValidator = new CmsValidator(truststoreWrapper); |
|
||||||
|
|
||||||
cmsValidatorWithoutCrl = new CmsValidator(truststoreWrapperWithoutCrl); |
|
||||||
} |
|
||||||
|
|
||||||
public KeyStore getKeystore() { |
|
||||||
return keystore; |
|
||||||
} |
|
||||||
|
|
||||||
public KeyStore getTruststore() { |
|
||||||
return truststore; |
|
||||||
} |
|
||||||
|
|
||||||
public List<X509CRL> getCRLs() { |
|
||||||
return CRLs; |
|
||||||
} |
|
||||||
|
|
||||||
public KeyStoreWrapper getKeystoreWrapper() { |
|
||||||
return keystoreWrapper; |
|
||||||
} |
|
||||||
|
|
||||||
public KeyStoreWrapper getTruststoreWrapper() { |
|
||||||
return truststoreWrapper; |
|
||||||
} |
|
||||||
|
|
||||||
public CmsValidator getCmsValidator() { |
|
||||||
return cmsValidator; |
|
||||||
} |
|
||||||
|
|
||||||
public KeyStoreWrapper getTruststoreWrapperWithoutCrl() { |
|
||||||
return truststoreWrapperWithoutCrl; |
|
||||||
} |
|
||||||
|
|
||||||
public CmsValidator getCmsValidatorWithoutCrl() { |
|
||||||
return cmsValidatorWithoutCrl; |
|
||||||
} |
|
||||||
} |
|
@ -1,156 +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 static org.junit.jupiter.api.Assertions.assertEquals; |
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull; |
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull; |
|
||||||
|
|
||||||
import java.nio.file.Path; |
|
||||||
import java.security.cert.Certificate; |
|
||||||
|
|
||||||
import org.junit.jupiter.params.ParameterizedTest; |
|
||||||
import org.junit.jupiter.params.provider.MethodSource; |
|
||||||
|
|
||||||
public abstract class BaseKeyStoreFileWrapperTest { |
|
||||||
protected static final String KEYSTORE_VALID_KEY_ALIAS = "partner1client1"; |
|
||||||
protected static final String KEYSTORE_INVALID_KEY_ALIAS = "partner1clientinvalid"; |
|
||||||
protected static final String TRUSTSTORE_VALID_CERTIFICATE_ALIAS = "interca"; |
|
||||||
protected static final String TRUSTSTORE_INVALID_CERTIFICATE_ALIAS = "interca-invalid"; |
|
||||||
|
|
||||||
protected static Path toPath(final String path) throws Exception { |
|
||||||
return null == path |
|
||||||
? null |
|
||||||
: Path.of(BaseKeyStoreFileWrapperTest.class.getResource(path).toURI()); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@MethodSource("data") |
|
||||||
public void getPublicKey_WithValidAlias_ReturnsExpectedValue( |
|
||||||
final KeyStoreWrapperTestParameter keyStoreWrapperTestParameter) { |
|
||||||
assertNotNull( |
|
||||||
keyStoreWrapperTestParameter.keyStoreWrapper.getPublicKey(KEYSTORE_VALID_KEY_ALIAS)); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@MethodSource("data") |
|
||||||
public void getPublicKey_WithInvalidAlias_ReturnsExpectedValue( |
|
||||||
final KeyStoreWrapperTestParameter keyStoreWrapperTestParameter) { |
|
||||||
assertNull( |
|
||||||
keyStoreWrapperTestParameter.keyStoreWrapper.getPublicKey(KEYSTORE_INVALID_KEY_ALIAS)); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@MethodSource("data") |
|
||||||
public void getPrivateKey_WithValidAlias_ReturnsExpectedValue( |
|
||||||
final KeyStoreWrapperTestParameter keyStoreWrapperTestParameter) { |
|
||||||
assertNotNull( |
|
||||||
keyStoreWrapperTestParameter.keyStoreWrapper.getPrivateKey(KEYSTORE_VALID_KEY_ALIAS), |
|
||||||
"Private key is not null"); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@MethodSource("data") |
|
||||||
public void getPrivateKey_WithInvalidAlias_ReturnsExpectedValue( |
|
||||||
final KeyStoreWrapperTestParameter keyStoreWrapperTestParameter) { |
|
||||||
assertNull( |
|
||||||
keyStoreWrapperTestParameter.keyStoreWrapper.getPrivateKey(KEYSTORE_INVALID_KEY_ALIAS), |
|
||||||
"Private key is null"); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@MethodSource("data") |
|
||||||
public void getCertificate_WithValidAlias_ReturnsExpectedValue( |
|
||||||
final KeyStoreWrapperTestParameter keyStoreWrapperTestParameter) { |
|
||||||
assertNotNull( |
|
||||||
keyStoreWrapperTestParameter.keyStoreWrapper.getCertificate(KEYSTORE_VALID_KEY_ALIAS), |
|
||||||
"Certificate is not null"); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@MethodSource("data") |
|
||||||
public void getCertificate_WithInvalidAlias_ReturnsExpectedValue( |
|
||||||
final KeyStoreWrapperTestParameter keyStoreWrapperTestParameter) { |
|
||||||
assertNull( |
|
||||||
keyStoreWrapperTestParameter.keyStoreWrapper.getCertificate(KEYSTORE_INVALID_KEY_ALIAS), |
|
||||||
"Certificate is null"); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@MethodSource("data") |
|
||||||
public void getCertificateChain_WithValidAlias_ReturnsExpectedValue( |
|
||||||
final KeyStoreWrapperTestParameter keyStoreWrapperTestParameter) { |
|
||||||
assertNotNull( |
|
||||||
keyStoreWrapperTestParameter.keyStoreWrapper.getCertificateChain(KEYSTORE_VALID_KEY_ALIAS), |
|
||||||
"Certificate chain is not null"); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@MethodSource("data") |
|
||||||
public void getCertificateChain_WithInvalidAlias_ReturnsExpectedValue( |
|
||||||
final KeyStoreWrapperTestParameter keyStoreWrapperTestParameter) { |
|
||||||
assertNull( |
|
||||||
keyStoreWrapperTestParameter.keyStoreWrapper.getCertificateChain( |
|
||||||
KEYSTORE_INVALID_KEY_ALIAS), |
|
||||||
"Certificate is null"); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@MethodSource("data") |
|
||||||
public void getCertificate_FromTruststore_WithValidAlias_ReturnsExpectedValue( |
|
||||||
final KeyStoreWrapperTestParameter keyStoreWrapperTestParameter) { |
|
||||||
final Certificate certificate = |
|
||||||
keyStoreWrapperTestParameter.keyStoreWrapper.getCertificate( |
|
||||||
TRUSTSTORE_VALID_CERTIFICATE_ALIAS); |
|
||||||
if (keyStoreWrapperTestParameter.keystoreWrapperConfiguredWithTruststore) { |
|
||||||
assertNotNull(certificate, "Certificate is not null"); |
|
||||||
} else { |
|
||||||
assertNull(certificate, "Certificate is null"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@MethodSource("data") |
|
||||||
public void getCertificate_FromTruststore_WithInvalidAlias_ReturnsExpectedValue( |
|
||||||
final KeyStoreWrapperTestParameter keyStoreWrapperTestParameter) { |
|
||||||
assertNull( |
|
||||||
keyStoreWrapperTestParameter.keyStoreWrapper.getPrivateKey( |
|
||||||
TRUSTSTORE_INVALID_CERTIFICATE_ALIAS), |
|
||||||
"Certificate is null"); |
|
||||||
} |
|
||||||
|
|
||||||
@ParameterizedTest |
|
||||||
@MethodSource("data") |
|
||||||
public void getCRLS_Check(final KeyStoreWrapperTestParameter keyStoreWrapperTestParameter) { |
|
||||||
assertNotNull(keyStoreWrapperTestParameter.keyStoreWrapper.getCRLs(), "CRLs is not null"); |
|
||||||
assertEquals( |
|
||||||
keyStoreWrapperTestParameter.keyStoreWrapper.getCRLs().size(), 2, "CRLs size matches"); |
|
||||||
} |
|
||||||
|
|
||||||
public static class KeyStoreWrapperTestParameter { |
|
||||||
public String keyStoreWrapperDescription; |
|
||||||
public boolean keystoreWrapperConfiguredWithTruststore; |
|
||||||
public KeyStoreWrapper keyStoreWrapper; |
|
||||||
|
|
||||||
public KeyStoreWrapperTestParameter( |
|
||||||
final String keyStoreWrapperDescription, |
|
||||||
final boolean keystoreWrapperConfiguredWithTruststore, |
|
||||||
final KeyStoreWrapper keyStoreWrapper) { |
|
||||||
this.keyStoreWrapperDescription = keyStoreWrapperDescription; |
|
||||||
this.keystoreWrapperConfiguredWithTruststore = keystoreWrapperConfiguredWithTruststore; |
|
||||||
this.keyStoreWrapper = keyStoreWrapper; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,81 +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.io.IOException; |
|
||||||
import java.nio.charset.StandardCharsets; |
|
||||||
import java.util.Optional; |
|
||||||
|
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
public class CryptoTestUtil { |
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(CryptoTestUtil.class); |
|
||||||
|
|
||||||
private CryptoTestUtil() {} |
|
||||||
|
|
||||||
public static boolean isNSSLibInstalled() { |
|
||||||
try { |
|
||||||
final String nssLibPath = getNSSLibPath(); |
|
||||||
return nssLibPath != null && !nssLibPath.trim().isEmpty(); |
|
||||||
} catch (final Exception e) { |
|
||||||
LOG.info("NSS library does not seem to be installed!", e); |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public static String getNSSLibPath() throws IOException, InterruptedException { |
|
||||||
String nssLibPath = ""; |
|
||||||
final String centOS_nssPathCmd = |
|
||||||
"whereis libnssdbm3 | grep -o \"\\/.*libnssdbm3\\.[0-9a-z]* \" | sed 's/\\/libnssdbm3.*//g'"; |
|
||||||
final String debian_nssPathCmd = |
|
||||||
"whereis libnss3 | grep -o \".*libnss3.[0-9a-z]\" | sed 's/lib.* \\(\\/.*\\)\\/lib.*/\\1/'"; |
|
||||||
final String macOS_nssPathCmd = "dirname `which certutil` | sed 's/bin/lib/g'"; |
|
||||||
|
|
||||||
nssLibPath = executeSystemCmd(centOS_nssPathCmd).orElse(nssLibPath); |
|
||||||
LOG.info("centOS_nssPathCmd: {}", nssLibPath); |
|
||||||
if ("".equals(nssLibPath)) { |
|
||||||
nssLibPath = executeSystemCmd(debian_nssPathCmd).orElse(nssLibPath); |
|
||||||
LOG.info("debian_nssPathCmd: {}", nssLibPath); |
|
||||||
} |
|
||||||
if ("".equals(nssLibPath)) { |
|
||||||
nssLibPath = executeSystemCmd(macOS_nssPathCmd).orElse(nssLibPath); |
|
||||||
LOG.info("macOS_nssPathCmd: {}", nssLibPath); |
|
||||||
} |
|
||||||
LOG.info("Detected NSS library path: {}", nssLibPath); |
|
||||||
return nssLibPath; |
|
||||||
} |
|
||||||
|
|
||||||
public static Optional<String> executeSystemCmd(final String cmd) |
|
||||||
throws IOException, InterruptedException { |
|
||||||
final Process p = Runtime.getRuntime().exec(new String[] {"/bin/sh", "-c", cmd}); |
|
||||||
try { |
|
||||||
if (p.waitFor() == 0) { |
|
||||||
final java.util.Scanner s = |
|
||||||
new java.util.Scanner(p.getInputStream(), StandardCharsets.UTF_8.name()) |
|
||||||
.useDelimiter("\\A"); |
|
||||||
if (s.hasNext()) { |
|
||||||
return Optional.of(s.next().replace("\r", "").replace("\n", "")); |
|
||||||
} |
|
||||||
} |
|
||||||
} finally { |
|
||||||
if (p != null) { |
|
||||||
p.destroy(); |
|
||||||
} |
|
||||||
} |
|
||||||
return Optional.empty(); |
|
||||||
} |
|
||||||
} |
|
@ -1,119 +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 static org.junit.jupiter.api.Assertions.assertThrows; |
|
||||||
import static org.junit.jupiter.api.Assumptions.assumeTrue; |
|
||||||
|
|
||||||
import org.hyperledger.besu.pki.PkiException; |
|
||||||
|
|
||||||
import java.nio.file.Path; |
|
||||||
import java.security.Provider; |
|
||||||
import java.security.Security; |
|
||||||
import java.util.Collection; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Optional; |
|
||||||
import java.util.stream.Stream; |
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assumptions; |
|
||||||
import org.junit.jupiter.api.BeforeAll; |
|
||||||
import org.junit.jupiter.api.BeforeEach; |
|
||||||
import org.junit.jupiter.api.Test; |
|
||||||
import org.junit.jupiter.api.condition.OS; |
|
||||||
|
|
||||||
public class HardwareKeyStoreFileWrapperTest extends BaseKeyStoreFileWrapperTest { |
|
||||||
|
|
||||||
private static final String config = "/keystore/partner1client1/nss.cfg"; |
|
||||||
private static final String crl = "/keystore/partner1client1/crl.pem"; |
|
||||||
private static final String configName = "NSScrypto-partner1client1"; |
|
||||||
private static final String validKeystorePassword = "test123"; |
|
||||||
private static KeyStoreWrapperTestParameter keyStoreWrapperTestParameter; |
|
||||||
|
|
||||||
@BeforeAll |
|
||||||
public static void setup() { |
|
||||||
keyStoreWrapperTestParameter = |
|
||||||
new KeyStoreWrapperTestParameter( |
|
||||||
"HardwareKeyStoreWrapper[PKCS11 keystore/truststore]", |
|
||||||
true, |
|
||||||
CryptoTestUtil.isNSSLibInstalled() ? getHardwareKeyStoreWrapper(configName) : null); |
|
||||||
} |
|
||||||
|
|
||||||
public static Collection<KeyStoreWrapperTestParameter> data() { |
|
||||||
return List.of(keyStoreWrapperTestParameter); |
|
||||||
} |
|
||||||
|
|
||||||
private static KeyStoreWrapper getHardwareKeyStoreWrapper(final String cfgName) { |
|
||||||
try { |
|
||||||
final Path path = toPath(config); |
|
||||||
final Path crlPath = toPath(crl); |
|
||||||
final Optional<Provider> existingProvider = |
|
||||||
Stream.of(Security.getProviders()) |
|
||||||
.filter(p -> p.getName().equals("SunPKCS11" + cfgName)) |
|
||||||
.findAny(); |
|
||||||
return existingProvider |
|
||||||
.map(provider -> new HardwareKeyStoreWrapper(validKeystorePassword, provider, crlPath)) |
|
||||||
.orElseGet(() -> new HardwareKeyStoreWrapper(validKeystorePassword, path, crlPath)); |
|
||||||
} catch (final Exception e) { |
|
||||||
// nss3 is difficult to setup on mac, don't let it break unit tests for dev machines.
|
|
||||||
Assumptions.assumeFalse( |
|
||||||
OS.MAC.isCurrentOs(), |
|
||||||
"Failed to initialize hardware keystore: " + e.getLocalizedMessage()); |
|
||||||
// Not a mac, probably a production build. Full failure.
|
|
||||||
throw new PkiException("Failed to initialize hardware keystore", e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@BeforeEach |
|
||||||
public void beforeMethod() { |
|
||||||
assumeTrue( |
|
||||||
CryptoTestUtil.isNSSLibInstalled(), |
|
||||||
"Test ignored due to NSS library not being installed/detected."); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getPkcs11Provider() throws Exception { |
|
||||||
final HardwareKeyStoreWrapper sut = |
|
||||||
(HardwareKeyStoreWrapper) getHardwareKeyStoreWrapper(configName); |
|
||||||
assertThrows( |
|
||||||
IllegalArgumentException.class, () -> sut.getPkcs11ProviderForConfig("no-library")); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void init_keystorePassword_config() throws Exception { |
|
||||||
new HardwareKeyStoreWrapper(validKeystorePassword, toPath(config), toPath(crl)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void init_keystorePassword_config_invalid() throws Exception { |
|
||||||
final String config = "invalid"; |
|
||||||
assertThrows( |
|
||||||
NullPointerException.class, |
|
||||||
() -> new HardwareKeyStoreWrapper(validKeystorePassword, toPath(config), toPath(crl))); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void init_keystorePassword_config_missing_pw() throws Exception { |
|
||||||
assertThrows( |
|
||||||
PkiException.class, () -> new HardwareKeyStoreWrapper(null, toPath(config), toPath(crl))); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void init_keystorePassword_provider_missing_pw() throws Exception { |
|
||||||
final Provider p = null; |
|
||||||
assertThrows( |
|
||||||
PkiException.class, |
|
||||||
() -> new HardwareKeyStoreWrapper(validKeystorePassword, p, toPath(crl))); |
|
||||||
} |
|
||||||
} |
|
@ -1,82 +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 static org.junit.jupiter.api.Assertions.assertEquals; |
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull; |
|
||||||
import static org.mockito.Mockito.when; |
|
||||||
|
|
||||||
import java.security.KeyStore; |
|
||||||
import java.security.PrivateKey; |
|
||||||
import java.security.PublicKey; |
|
||||||
import java.security.cert.Certificate; |
|
||||||
|
|
||||||
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; |
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class) |
|
||||||
public class HardwareKeyStoreWrapperTest { |
|
||||||
|
|
||||||
private static final String KEY_ALIAS = "keyalias"; |
|
||||||
private static final String CERTIFICATE_ALIAS = "certalias"; |
|
||||||
private static final char[] PASSWORD = "password".toCharArray(); |
|
||||||
|
|
||||||
@Mock private KeyStore keyStore; |
|
||||||
@Mock private PrivateKey privateKey; |
|
||||||
@Mock private PublicKey publicKey; |
|
||||||
@Mock private Certificate certificate; |
|
||||||
|
|
||||||
private HardwareKeyStoreWrapper keyStoreWrapper; |
|
||||||
|
|
||||||
@BeforeEach |
|
||||||
public void before() { |
|
||||||
keyStoreWrapper = new HardwareKeyStoreWrapper(null, keyStore, new String(PASSWORD)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getPrivateKey() throws Exception { |
|
||||||
when(keyStore.getKey(KEY_ALIAS, PASSWORD)).thenReturn(privateKey); |
|
||||||
|
|
||||||
assertNotNull(keyStoreWrapper.getPrivateKey(KEY_ALIAS)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getPublicKey() throws Exception { |
|
||||||
// Get public key from certificate
|
|
||||||
when(keyStore.getCertificate(KEY_ALIAS)).thenReturn(certificate); |
|
||||||
when(certificate.getPublicKey()).thenReturn(publicKey); |
|
||||||
|
|
||||||
assertNotNull(keyStoreWrapper.getPublicKey(KEY_ALIAS)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getCertificate() throws Exception { |
|
||||||
when(keyStore.getCertificate(CERTIFICATE_ALIAS)).thenReturn(certificate); |
|
||||||
|
|
||||||
assertNotNull(keyStoreWrapper.getCertificate(CERTIFICATE_ALIAS)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getCertificateChain() throws Exception { |
|
||||||
when(keyStore.getCertificateChain(CERTIFICATE_ALIAS)) |
|
||||||
.thenReturn(new Certificate[] {certificate}); |
|
||||||
|
|
||||||
assertEquals(keyStoreWrapper.getCertificateChain(CERTIFICATE_ALIAS).length, 1); |
|
||||||
} |
|
||||||
} |
|
@ -1,80 +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.nio.file.Path; |
|
||||||
import java.util.Arrays; |
|
||||||
import java.util.Collection; |
|
||||||
|
|
||||||
public class SoftwareKeyStoreFileWrapperTest extends BaseKeyStoreFileWrapperTest { |
|
||||||
|
|
||||||
private static final String p12KeyStore = "/keystore/partner1client1/keys.p12"; |
|
||||||
private static final String jksKeyStore = "/keystore/partner1client1/keystore.jks"; |
|
||||||
private static final String trustStore = "/keystore/partner1client1/truststore.jks"; |
|
||||||
private static final String crl = "/keystore/partner1client1/crl.pem"; |
|
||||||
private static final String validKeystorePassword = "test123"; |
|
||||||
|
|
||||||
public static Collection<KeyStoreWrapperTestParameter> data() { |
|
||||||
return Arrays.asList( |
|
||||||
new KeyStoreWrapperTestParameter( |
|
||||||
"SoftwareKeyStoreWrapper[PKCS12 keystore only]", |
|
||||||
false, |
|
||||||
getPKCS12SoftwareKeyStoreWrapper()), |
|
||||||
new KeyStoreWrapperTestParameter( |
|
||||||
"SoftwareKeyStoreWrapper[JKS keystore only]", |
|
||||||
false, |
|
||||||
getJKSSoftwareKeyStoreWrapper(false)), |
|
||||||
new KeyStoreWrapperTestParameter( |
|
||||||
"SoftwareKeyStoreWrapper[JKS keystore/truststore]", |
|
||||||
true, |
|
||||||
getJKSSoftwareKeyStoreWrapper(true))); |
|
||||||
} |
|
||||||
|
|
||||||
private static KeyStoreWrapper getPKCS12SoftwareKeyStoreWrapper() { |
|
||||||
try { |
|
||||||
return new SoftwareKeyStoreWrapper( |
|
||||||
KeyStoreWrapper.KEYSTORE_TYPE_PKCS12, |
|
||||||
toPath(p12KeyStore), |
|
||||||
validKeystorePassword, |
|
||||||
toPath(crl)); |
|
||||||
} catch (final Exception e) { |
|
||||||
throw new PkiException("Failed to initialize software keystore", e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private static KeyStoreWrapper getJKSSoftwareKeyStoreWrapper(final boolean setupTruststore) { |
|
||||||
try { |
|
||||||
final Path keystoreLocation = toPath(jksKeyStore); |
|
||||||
if (setupTruststore) { |
|
||||||
final Path truststoreLocation = toPath(trustStore); |
|
||||||
// password shouldn't be needed for retrieving certificate from truststore
|
|
||||||
return new SoftwareKeyStoreWrapper( |
|
||||||
KeyStoreWrapper.KEYSTORE_TYPE_JKS, |
|
||||||
keystoreLocation, |
|
||||||
validKeystorePassword, |
|
||||||
KeyStoreWrapper.KEYSTORE_TYPE_JKS, |
|
||||||
truststoreLocation, |
|
||||||
null, |
|
||||||
toPath(crl)); |
|
||||||
} |
|
||||||
return new SoftwareKeyStoreWrapper( |
|
||||||
KeyStoreWrapper.KEYSTORE_TYPE_JKS, keystoreLocation, validKeystorePassword, toPath(crl)); |
|
||||||
} catch (final Exception e) { |
|
||||||
throw new PkiException("Failed to initialize software keystore", e); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,198 +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 static org.hyperledger.besu.pki.keystore.KeyStoreWrapper.KEYSTORE_TYPE_PKCS12; |
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals; |
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull; |
|
||||||
import static org.mockito.ArgumentMatchers.eq; |
|
||||||
import static org.mockito.Mockito.times; |
|
||||||
import static org.mockito.Mockito.verify; |
|
||||||
import static org.mockito.Mockito.when; |
|
||||||
|
|
||||||
import java.nio.file.Path; |
|
||||||
import java.security.KeyStore; |
|
||||||
import java.security.PrivateKey; |
|
||||||
import java.security.PublicKey; |
|
||||||
import java.security.cert.Certificate; |
|
||||||
|
|
||||||
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; |
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class) |
|
||||||
public class SoftwareKeyStoreWrapperTest { |
|
||||||
|
|
||||||
private static final String KEY_ALIAS = "keyalias"; |
|
||||||
private static final String CERTIFICATE_ALIAS = "certalias"; |
|
||||||
private static final char[] PASSWORD = "password".toCharArray(); |
|
||||||
|
|
||||||
private SoftwareKeyStoreWrapper keyStoreWrapper; |
|
||||||
|
|
||||||
@Mock private KeyStore keyStore; |
|
||||||
@Mock private KeyStore trustStore; |
|
||||||
@Mock private PrivateKey privateKey; |
|
||||||
@Mock private PublicKey publicKey; |
|
||||||
@Mock private Certificate certificate; |
|
||||||
|
|
||||||
@BeforeEach |
|
||||||
public void before() { |
|
||||||
keyStoreWrapper = new SoftwareKeyStoreWrapper(keyStore, new String(PASSWORD), null, ""); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getPrivateKey() throws Exception { |
|
||||||
when(keyStore.containsAlias(KEY_ALIAS)).thenReturn(true); |
|
||||||
when(keyStore.getKey(KEY_ALIAS, PASSWORD)).thenReturn(privateKey); |
|
||||||
|
|
||||||
assertNotNull(keyStoreWrapper.getPrivateKey(KEY_ALIAS)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getPrivateKeyCaching() throws Exception { |
|
||||||
when(keyStore.containsAlias(KEY_ALIAS)).thenReturn(true); |
|
||||||
when(keyStore.getKey(KEY_ALIAS, PASSWORD)).thenReturn(privateKey); |
|
||||||
|
|
||||||
keyStoreWrapper.getPrivateKey(KEY_ALIAS); |
|
||||||
keyStoreWrapper.getPrivateKey(KEY_ALIAS); |
|
||||||
|
|
||||||
verify(keyStore, times(1)).getKey(eq(KEY_ALIAS), eq(PASSWORD)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getPrivateKeyFallbackToTrustStore() throws Exception { |
|
||||||
keyStoreWrapper = |
|
||||||
new SoftwareKeyStoreWrapper( |
|
||||||
keyStore, new String(PASSWORD), trustStore, new String(PASSWORD)); |
|
||||||
|
|
||||||
when(keyStore.containsAlias(KEY_ALIAS)).thenReturn(false); |
|
||||||
when(trustStore.containsAlias(KEY_ALIAS)).thenReturn(true); |
|
||||||
when(trustStore.getKey(KEY_ALIAS, PASSWORD)).thenReturn(privateKey); |
|
||||||
|
|
||||||
assertNotNull(keyStoreWrapper.getPrivateKey(KEY_ALIAS)); |
|
||||||
|
|
||||||
verify(trustStore).getKey(eq(KEY_ALIAS), eq(PASSWORD)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getPublicKey() throws Exception { |
|
||||||
when(keyStore.containsAlias(KEY_ALIAS)).thenReturn(true); |
|
||||||
when(keyStore.getKey(KEY_ALIAS, PASSWORD)).thenReturn(publicKey); |
|
||||||
|
|
||||||
assertNotNull(keyStoreWrapper.getPublicKey(KEY_ALIAS)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getPublicKeyCaching() throws Exception { |
|
||||||
when(keyStore.containsAlias(KEY_ALIAS)).thenReturn(true); |
|
||||||
when(keyStore.getKey(KEY_ALIAS, PASSWORD)).thenReturn(publicKey); |
|
||||||
|
|
||||||
keyStoreWrapper.getPublicKey(KEY_ALIAS); |
|
||||||
keyStoreWrapper.getPublicKey(KEY_ALIAS); |
|
||||||
|
|
||||||
verify(keyStore, times(1)).getKey(eq(KEY_ALIAS), eq(PASSWORD)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getPublicKeyFallbackToTrustStore() throws Exception { |
|
||||||
keyStoreWrapper = |
|
||||||
new SoftwareKeyStoreWrapper( |
|
||||||
keyStore, new String(PASSWORD), trustStore, new String(PASSWORD)); |
|
||||||
|
|
||||||
when(keyStore.containsAlias(KEY_ALIAS)).thenReturn(false); |
|
||||||
when(trustStore.containsAlias(KEY_ALIAS)).thenReturn(true); |
|
||||||
when(trustStore.getKey(KEY_ALIAS, PASSWORD)).thenReturn(publicKey); |
|
||||||
|
|
||||||
assertNotNull(keyStoreWrapper.getPublicKey(KEY_ALIAS)); |
|
||||||
|
|
||||||
verify(trustStore).getKey(eq(KEY_ALIAS), eq(PASSWORD)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getCertificate() throws Exception { |
|
||||||
when(keyStore.getCertificate(CERTIFICATE_ALIAS)).thenReturn(certificate); |
|
||||||
|
|
||||||
assertNotNull(keyStoreWrapper.getCertificate(CERTIFICATE_ALIAS)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getCertificateCaching() throws Exception { |
|
||||||
when(keyStore.getCertificate(CERTIFICATE_ALIAS)).thenReturn(certificate); |
|
||||||
|
|
||||||
keyStoreWrapper.getCertificate(CERTIFICATE_ALIAS); |
|
||||||
keyStoreWrapper.getCertificate(CERTIFICATE_ALIAS); |
|
||||||
|
|
||||||
verify(keyStore, times(1)).getCertificate(eq(CERTIFICATE_ALIAS)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getCertificateFallbackToTrustStore() throws Exception { |
|
||||||
keyStoreWrapper = |
|
||||||
new SoftwareKeyStoreWrapper( |
|
||||||
keyStore, new String(PASSWORD), trustStore, new String(PASSWORD)); |
|
||||||
|
|
||||||
when(keyStore.getCertificate(CERTIFICATE_ALIAS)).thenReturn(null); |
|
||||||
when(trustStore.getCertificate(CERTIFICATE_ALIAS)).thenReturn(certificate); |
|
||||||
|
|
||||||
assertNotNull(keyStoreWrapper.getCertificate(CERTIFICATE_ALIAS)); |
|
||||||
|
|
||||||
verify(trustStore).getCertificate(eq(CERTIFICATE_ALIAS)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getCertificateChain() throws Exception { |
|
||||||
when(keyStore.getCertificateChain(CERTIFICATE_ALIAS)) |
|
||||||
.thenReturn(new Certificate[] {certificate}); |
|
||||||
|
|
||||||
assertEquals(keyStoreWrapper.getCertificateChain(CERTIFICATE_ALIAS).length, 1); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getCertificateChainFallbackToTrustStore() throws Exception { |
|
||||||
keyStoreWrapper = |
|
||||||
new SoftwareKeyStoreWrapper( |
|
||||||
keyStore, new String(PASSWORD), trustStore, new String(PASSWORD)); |
|
||||||
|
|
||||||
when(keyStore.getCertificateChain(CERTIFICATE_ALIAS)).thenReturn(null); |
|
||||||
when(trustStore.getCertificateChain(CERTIFICATE_ALIAS)) |
|
||||||
.thenReturn(new Certificate[] {certificate}); |
|
||||||
|
|
||||||
assertEquals(keyStoreWrapper.getCertificateChain(CERTIFICATE_ALIAS).length, 1); |
|
||||||
|
|
||||||
verify(trustStore).getCertificateChain(eq(CERTIFICATE_ALIAS)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void loadKeyStoreFromFile() { |
|
||||||
SoftwareKeyStoreWrapper loadedKeyStore = |
|
||||||
new SoftwareKeyStoreWrapper( |
|
||||||
KEYSTORE_TYPE_PKCS12, |
|
||||||
Path.of("src/test/resources/keystore/keystore"), |
|
||||||
"validator", |
|
||||||
KEYSTORE_TYPE_PKCS12, |
|
||||||
Path.of("src/test/resources/keystore/keystore"), |
|
||||||
"validator", |
|
||||||
null); |
|
||||||
|
|
||||||
assertNotNull(loadedKeyStore.getPublicKey("validator")); |
|
||||||
assertNotNull(loadedKeyStore.getPrivateKey("validator")); |
|
||||||
assertNotNull(loadedKeyStore.getCertificate("validator")); |
|
||||||
// CA -> INTERCA -> PARTNERACA -> VALIDATOR
|
|
||||||
assertEquals(loadedKeyStore.getCertificateChain("validator").length, 4); |
|
||||||
} |
|
||||||
} |
|
Binary file not shown.
Binary file not shown.
@ -1,6 +0,0 @@ |
|||||||
|
|
||||||
name = NSScrypto-partner1client1 |
|
||||||
nssSecmodDirectory = ./src/test/resources/keystore/partner1client1/nssdb |
|
||||||
nssDbMode = readOnly |
|
||||||
nssModule = keystore |
|
||||||
|
|
Binary file not shown.
Loading…
Reference in new issue