├── .circleci └── config.yml ├── .gitignore ├── CHANGELOG.md ├── CLA.md ├── CODE-OF-CONDUCT.md ├── CODING-CONVENTIONS.md ├── CONTRIBUTING.md ├── GOVERNANCE.md ├── LICENSE ├── README.md ├── acceptance-tests ├── build.gradle └── src │ ├── test │ ├── java │ │ └── tech │ │ │ └── pegasys │ │ │ └── signers │ │ │ ├── keystorage │ │ │ └── hashicorp │ │ │ │ └── tests │ │ │ │ └── HashicorpVaultAccessAcceptanceTest.java │ │ │ └── secp256k1 │ │ │ └── tests │ │ │ └── multikey │ │ │ ├── AzureBasedTomlLoadingAcceptanceTest.java │ │ │ ├── FileBasedTomlLoadingAcceptanceTest.java │ │ │ ├── HashicorpBasedTomlLoadingAcceptanceTest.java │ │ │ ├── HashicorpHelpers.java │ │ │ ├── HashicorpTlsBasedTomlLoadingAcceptanceTest.java │ │ │ ├── MultiKeyAcceptanceTestBase.java │ │ │ └── signing │ │ │ ├── MultiKeyAzureTransactionSignerAcceptanceTest.java │ │ │ ├── MultiKeyFileBasedTransactionSignerAcceptanceTest.java │ │ │ ├── MultiKeyHashicorpTransactionSignerAcceptanceTest.java │ │ │ └── MultiKeyTransactionSigningAcceptanceTestBase.java │ └── resources │ │ ├── log4j2.xml │ │ └── secp256k1 │ │ ├── UTC--2019-12-05T05-17-11.151993000Z--a01f618424b0113a9cebdc6cb66ca5b48e9120c5.key │ │ ├── UTC--2019-12-05T05-17-11.151993000Z--a01f618424b0113a9cebdc6cb66ca5b48e9120c5.password │ │ └── rich_benefactor_one.json │ └── testFixtures │ └── java │ └── tech.pegasys.signers.secp256k1 │ ├── AllTomlConfigFilesSelector.java │ ├── HashicorpSigningParams.java │ ├── MultiKeyTomlFileUtil.java │ └── SignerIdentifierConfigFileSelector.java ├── bls-keystore ├── build.gradle └── src │ ├── main │ └── java │ │ └── tech │ │ └── pegasys │ │ └── signers │ │ └── bls │ │ └── keystore │ │ ├── KeyStore.java │ │ ├── KeyStoreBytesModule.java │ │ ├── KeyStoreLoader.java │ │ ├── KeyStoreValidationException.java │ │ ├── PasswordUtils.java │ │ └── model │ │ ├── Checksum.java │ │ ├── ChecksumFunction.java │ │ ├── Cipher.java │ │ ├── CipherFunction.java │ │ ├── CipherParam.java │ │ ├── Crypto.java │ │ ├── EmptyParam.java │ │ ├── Kdf.java │ │ ├── KdfFunction.java │ │ ├── KdfParam.java │ │ ├── KeyStoreData.java │ │ ├── Pbkdf2Param.java │ │ ├── Pbkdf2PseudoRandomFunction.java │ │ └── SCryptParam.java │ └── test │ ├── java │ └── tech │ │ └── pegasys │ │ └── signers │ │ └── bls │ │ └── keystore │ │ ├── DecryptionKeyTest.java │ │ ├── KeyStoreTest.java │ │ ├── PasswordUtilsTest.java │ │ └── model │ │ └── CipherTest.java │ └── resources │ ├── missingKdfSectionTestVector.json │ ├── pbkdf2TestVector.json │ ├── scryptExtraFieldTestVector.json │ ├── scryptTestVector.json │ ├── scryptTestVectorWithMissingPathAndUUID.json │ ├── unsupportedChecksumFunction.json │ ├── unsupportedCipherFunction.json │ ├── unsupportedDkLen.json │ ├── unsupportedKdfFunction.json │ ├── unsupportedPBKDF2Prf.json │ └── v3TestVector.json ├── build.gradle ├── gradle.properties ├── gradle ├── eclipse-java-google-style.xml ├── formatter.properties ├── license-report-config │ ├── allowed-licenses.json │ └── license-normalizer.json ├── owasp-suppression.xml ├── spotless.bash.license ├── spotless.java.license ├── versions.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── keystorage ├── aws │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── tech │ │ │ └── pegasys │ │ │ └── signers │ │ │ └── aws │ │ │ ├── AwsKeyIdentifier.java │ │ │ ├── AwsSecretsManager.java │ │ │ └── AwsSecretsManagerProvider.java │ │ └── test │ │ └── java │ │ └── tech │ │ └── pegasys │ │ └── signers │ │ └── aws │ │ ├── AwsSecret.java │ │ ├── AwsSecretsManagerProviderTest.java │ │ ├── AwsSecretsManagerTest.java │ │ └── SecretsMaps.java ├── azure │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── tech │ │ │ └── pegasys │ │ │ └── signers │ │ │ └── azure │ │ │ └── AzureKeyVault.java │ │ └── test │ │ └── java │ │ └── tech │ │ └── pegasys │ │ └── signers │ │ └── azure │ │ └── AzureKeyVaultTest.java ├── build.gradle ├── common │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── tech │ │ │ └── pegasys │ │ │ └── signers │ │ │ └── common │ │ │ ├── MappedResults.java │ │ │ └── SecretValueMapperUtil.java │ │ └── test │ │ └── java │ │ └── tech │ │ └── pegasys │ │ └── signers │ │ └── common │ │ └── SecretValueMapperUtilTest.java ├── hashicorp │ ├── build.gradle │ └── src │ │ ├── integrationTest │ │ └── java │ │ │ └── tech │ │ │ └── pegasys │ │ │ └── signers │ │ │ └── hashicorp │ │ │ └── HashicorpIntegrationTest.java │ │ ├── main │ │ └── java │ │ │ └── tech │ │ │ └── pegasys │ │ │ └── signers │ │ │ └── hashicorp │ │ │ ├── HashicorpConnection.java │ │ │ ├── HashicorpConnectionFactory.java │ │ │ ├── HashicorpException.java │ │ │ ├── HashicorpKVResponseMapper.java │ │ │ ├── TrustManagerFactoryProvider.java │ │ │ ├── TrustStoreType.java │ │ │ └── config │ │ │ ├── ConnectionParameters.java │ │ │ ├── HashicorpKeyConfig.java │ │ │ ├── KeyDefinition.java │ │ │ ├── TlsOptions.java │ │ │ └── loader │ │ │ └── toml │ │ │ ├── TomlConfigLoader.java │ │ │ └── TomlParser.java │ │ ├── test │ │ ├── java │ │ │ └── tech │ │ │ │ └── pegasys │ │ │ │ └── signers │ │ │ │ └── hashicorp │ │ │ │ ├── HashicorpConnectionFactoryTest.java │ │ │ │ ├── HashicorpConnectionTest.java │ │ │ │ ├── HashicorpKVResponseMapperTest.java │ │ │ │ ├── TrustStoreTypeTest.java │ │ │ │ └── loader │ │ │ │ └── TomlConfigLoaderTest.java │ │ └── resources │ │ │ └── tls │ │ │ └── cert1.pfx │ │ └── testFixtures │ │ └── java │ │ └── tech │ │ └── pegasys │ │ └── signers │ │ └── hashicorp │ │ ├── dsl │ │ ├── HashicorpNode.java │ │ ├── HashicorpVaultCommands.java │ │ ├── HashicorpVaultTokens.java │ │ └── certificates │ │ │ ├── CertificateHelpers.java │ │ │ └── SelfSignedCertificate.java │ │ └── util │ │ └── HashicorpConfigUtil.java ├── interlock │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── tech │ │ │ └── pegasys │ │ │ └── signers │ │ │ └── interlock │ │ │ ├── InterlockClientException.java │ │ │ ├── InterlockSession.java │ │ │ ├── InterlockSessionFactory.java │ │ │ ├── InterlockSessionFactoryProvider.java │ │ │ ├── model │ │ │ └── ApiAuth.java │ │ │ └── vertx │ │ │ ├── InterlockSessionFactoryImpl.java │ │ │ ├── InterlockSessionImpl.java │ │ │ └── operations │ │ │ ├── AbstractOperation.java │ │ │ ├── ApiOperation.java │ │ │ ├── FileDownloadIdOperation.java │ │ │ ├── FileDownloadOperation.java │ │ │ ├── LoginOperation.java │ │ │ └── LogoutOperation.java │ │ └── test │ │ ├── java │ │ └── tech │ │ │ └── pegasys │ │ │ └── signers │ │ │ └── interlock │ │ │ └── InterlockClientTest.java │ │ └── resources │ │ └── log4j2-test.xml └── yubihsm2 │ ├── build.gradle │ └── src │ ├── main │ └── java │ │ └── tech │ │ └── pegasys │ │ └── signers │ │ └── yubihsm │ │ ├── YubiHsm.java │ │ ├── YubiHsmException.java │ │ └── pkcs11 │ │ ├── ExtendedData.java │ │ ├── Pkcs11Module.java │ │ ├── Pkcs11Session.java │ │ ├── Pkcs11YubiHsm.java │ │ └── Pkcs11YubiHsmPin.java │ └── test │ ├── java │ └── tech │ │ └── pegasys │ │ └── signers │ │ └── yubihsm │ │ └── ManualYubiHsmPKCS11Test.java │ └── resources │ └── log4j2-test.xml ├── settings.gradle └── signing ├── build.gradle └── secp256k1 ├── api ├── build.gradle └── src │ └── main │ └── java │ └── tech │ └── pegasys │ └── signers │ └── secp256k1 │ └── api │ ├── FileSelector.java │ ├── Signature.java │ ├── Signer.java │ ├── SignerIdentifier.java │ ├── SignerProvider.java │ ├── SingleSignerProvider.java │ └── util │ └── AddressUtil.java ├── build.gradle └── impl ├── build.gradle └── src ├── main └── java │ └── tech │ └── pegasys │ └── signers │ └── secp256k1 │ ├── EthPublicKeyUtils.java │ ├── azure │ ├── AzureConfig.java │ ├── AzureKeyVaultSigner.java │ └── AzureKeyVaultSignerFactory.java │ ├── common │ ├── PasswordFileUtil.java │ └── SignerInitializationException.java │ ├── filebased │ ├── CredentialSigner.java │ ├── FileBasedSignerFactory.java │ └── FileSignerConfig.java │ ├── hashicorp │ └── HashicorpSignerFactory.java │ └── multikey │ ├── MultiKeySignerProvider.java │ ├── MultiSignerFactory.java │ ├── SignerType.java │ ├── SigningMetadataTomlConfigLoader.java │ ├── TomlConfigFileParser.java │ ├── TomlTableAdapter.java │ └── metadata │ ├── AzureSigningMetadataFile.java │ ├── FileBasedSigningMetadataFile.java │ ├── HashicorpSigningMetadataFile.java │ ├── RawSigningMetadataFile.java │ └── SigningMetadataFile.java ├── test ├── java │ └── tech │ │ └── pegasys │ │ └── signers │ │ └── secp256k1 │ │ ├── EthPublicKeyUtilsTest.java │ │ ├── azure │ │ └── AzureKeyVaultSignerTest.java │ │ ├── common │ │ └── PasswordFileUtilTest.java │ │ ├── filebased │ │ ├── CredentialSignerTest.java │ │ └── FileBasedSignerTest.java │ │ └── multikey │ │ ├── FileBasedSigningMetadataFileTest.java │ │ ├── HashicorpSigningMetadataTomlConfigLoaderTest.java │ │ ├── MetadataFileFixture.java │ │ ├── MultiKeySignerProviderTest.java │ │ └── SigningMetadataTomlConfigLoaderTest.java └── resources │ └── metadata-toml-configs │ ├── 627306090abab3a6e1400e9345bc60c78a8bef57.toml │ ├── UTC--2019-10-23T04-00-04.860366000Z--f17f52151ebef6c7334fad080c5704d77216b732.toml │ ├── azureconfig.toml │ ├── azureconfig_illegalValueType.toml │ ├── azureconfig_missingField.toml │ ├── bar_fe3b557e8fb62b89f4916b721be55ceb828dbd73.toml │ ├── duplicate_bar_627306090abab3a6e1400e9345bc60c78a8bef61.toml │ ├── duplicate_foo_627306090abab3a6e1400e9345bc60c78a8bef61.toml │ ├── k.key │ ├── key_password_relative_path.toml │ ├── missing_key_and_password_file_fe3b557e8fb62b89f4916b721be55ceb828dbd78.toml │ ├── missing_key_file_fe3b557e8fb62b89f4916b721be55ceb828dbd76.toml │ ├── missing_password_file_fe3b557e8fb62b89f4916b721be55ceb828dbd77.toml │ ├── p.password │ └── unknown_type_signer_fe3b557e8fb62b89f4916b721be55ceb828dbd75.toml └── testFixtures └── java └── tech └── pegasys └── signers └── secp256k1 └── common ├── PublicKeySignerIdentifier.java └── TomlStringBuilder.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.bak 2 | *.swp 3 | *.tmp 4 | *~.nib 5 | *.iml 6 | *.launch 7 | *.swp 8 | *.log 9 | .classpath 10 | .DS_Store 11 | .externalToolBuilders/ 12 | .gradle/ 13 | .idea/ 14 | .loadpath 15 | .metadata 16 | .prefs 17 | .project 18 | .recommenders/ 19 | .settings 20 | .springBeans 21 | .vertx 22 | bin/ 23 | local.properties 24 | target/ 25 | tmp/ 26 | build/ 27 | out/ 28 | docker/reports/* 29 | -------------------------------------------------------------------------------- /CLA.md: -------------------------------------------------------------------------------- 1 | Sign the CLA 2 | ============= 3 | 4 | This page is the step-by-step guide to signing the Consensys Software Inc. 5 | Individual Contributor License Agreement. 6 | 7 | 1. First and foremost, read [the current version of the CLA]. 8 | It is written to be as close to plain English as possible. 9 | 10 | 2. Make an account on [GitHub] if you don't already have one. 11 | 12 | 3. After creating your first pull request, you will see a merge 13 | pre-requisite requiring to you read and sign the CLA. 14 | 15 | If you have any questions, you can reach us on [Gitter]. 16 | 17 | [GitHub]: https://github.com/ 18 | [the current version of the CLA]: https://gist.github.com/rojotek/978b48a5e8b68836856a8961d6887992 19 | -------------------------------------------------------------------------------- /GOVERNANCE.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | This project is led by a benevolent dictator (ConsenSys) and managed by the community. That is, the 3 | community actively contributes to the day-to-day maintenance of the project, but the general 4 | strategic line is drawn by the benevolent dictator. In case of disagreement, they have the last word. 5 | It is the benevolent dictator’s job to resolve disputes within the community and to ensure that the 6 | project is able to progress in a coordinated way. In turn, it is the community’s job to guide the 7 | decisions of the benevolent dictator through active engagement and contribution. 8 | 9 | 10 | # Principles 11 | 12 | The community adheres to the following principles: 13 | * Open: Signers is open source. See repository guidelines and CLA, below. 14 | * Welcoming and respectful: See Code of Conduct, below. 15 | * Transparent and accessible: Work and collaboration should be done in public. 16 | * Merit: Ideas and contributions are accepted according to their technical merit and alignment with 17 | project objectives and design principles. 18 | 19 | # Code of Conduct 20 | See [code of conduct] 21 | 22 | # Community membership 23 | 24 | See [community membership] 25 | 26 | # Decision Making 27 | Decision making will be handled by the Approvers (see [community membership]). If consensus cannot 28 | be reached, the Benevolent Dictator will provide the final word on the decision. 29 | 30 | 31 | # CLA 32 | 33 | All contributors must sign the CLA, as described in [CLA.md]. 34 | ## Attribution 35 | 36 | This document was influenced by the following: 37 | - Kubernetes community-membership.md, available at [kub community membership]. 38 | - Kubernetes governance.md, available at [kub governance] 39 | - OSSWatch Benevolent Dictator Governance Model, available at [oss watch benevolent dictator]. 40 | 41 | [CLA.md]: /CLA.md 42 | [code of conduct]: /CODE-OF-CONDUCT.md 43 | [oss watch benevolent dictator]: http://oss-watch.ac.uk/resources/benevolentdictatorgovernancemodel 44 | [kub community membership]: https://raw.githubusercontent.com/kubernetes/community/master/community-membership.md 45 | [kub governance]:https://github.com/kubernetes/community/blob/master/governance.md 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Signers 2 | 3 | ## Description 4 | A library of utilities which aid in handling keys and signing operations. 5 | -------------------------------------------------------------------------------- /acceptance-tests/src/test/java/tech/pegasys/signers/secp256k1/tests/multikey/AzureBasedTomlLoadingAcceptanceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.tests.multikey; 14 | 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | import static tech.pegasys.signers.secp256k1.MultiKeyTomlFileUtil.createAzureTomlFileAt; 17 | 18 | import tech.pegasys.signers.secp256k1.EthPublicKeyUtils; 19 | import tech.pegasys.signers.secp256k1.common.PublicKeySignerIdentifier; 20 | 21 | import java.nio.file.Path; 22 | 23 | import org.junit.jupiter.api.Assumptions; 24 | import org.junit.jupiter.api.BeforeAll; 25 | import org.junit.jupiter.api.Test; 26 | import org.junit.jupiter.api.io.TempDir; 27 | 28 | public class AzureBasedTomlLoadingAcceptanceTest extends MultiKeyAcceptanceTestBase { 29 | 30 | static final String clientId = System.getenv("AZURE_CLIENT_ID"); 31 | static final String clientSecret = System.getenv("AZURE_CLIENT_SECRET"); 32 | static final String keyVaultName = System.getenv("AZURE_KEY_VAULT_NAME"); 33 | static final String tenantId = System.getenv("AZURE_TENANT_ID"); 34 | // TestKey2 35 | public static final String PUBLIC_KEY_HEX_STRING = 36 | "964f00253459f1f43c7a7720a0db09a328d4ee6f18838015023135d7fc921f1448de34d05de7a1f72a7b5c9f6c76931d7ab33d0f0846ccce5452063bd20f5809"; 37 | 38 | @BeforeAll 39 | static void preChecks() { 40 | Assumptions.assumeTrue( 41 | clientId != null && clientSecret != null && keyVaultName != null && tenantId != null, 42 | "Ensure Azure env variables are set"); 43 | } 44 | 45 | @Test 46 | void azureSignersAreCreatedAndExpectedAddressIsReported(@TempDir Path tomlDirectory) { 47 | createAzureTomlFileAt( 48 | tomlDirectory.resolve(PUBLIC_KEY_HEX_STRING + ".toml"), 49 | clientId, 50 | clientSecret, 51 | keyVaultName, 52 | tenantId); 53 | 54 | setup(tomlDirectory); 55 | 56 | assertThat( 57 | signerProvider.availablePublicKeys(PublicKeySignerIdentifier::new).stream() 58 | .map(EthPublicKeyUtils::toHexString)) 59 | .containsOnly("0x" + PUBLIC_KEY_HEX_STRING); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /acceptance-tests/src/test/java/tech/pegasys/signers/secp256k1/tests/multikey/HashicorpBasedTomlLoadingAcceptanceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.tests.multikey; 14 | 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | import static tech.pegasys.signers.secp256k1.MultiKeyTomlFileUtil.createHashicorpTomlFileAt; 17 | 18 | import tech.pegasys.signers.secp256k1.EthPublicKeyUtils; 19 | import tech.pegasys.signers.secp256k1.HashicorpSigningParams; 20 | import tech.pegasys.signers.secp256k1.common.PublicKeySignerIdentifier; 21 | 22 | import java.nio.file.Path; 23 | 24 | import org.junit.jupiter.api.AfterAll; 25 | import org.junit.jupiter.api.BeforeAll; 26 | import org.junit.jupiter.api.Test; 27 | import org.junit.jupiter.api.io.TempDir; 28 | 29 | class HashicorpBasedTomlLoadingAcceptanceTest extends MultiKeyAcceptanceTestBase { 30 | 31 | public static final String PUBLIC_KEY_HEX_STRING = 32 | "09b02f8a5fddd222ade4ea4528faefc399623af3f736be3c44f03e2df22fb792f3931a4d9573d333ca74343305762a753388c3422a86d98b713fc91c1ea04842"; 33 | 34 | private static HashicorpSigningParams hashicorpNode; 35 | 36 | @BeforeAll 37 | static void setUpBase() { 38 | hashicorpNode = HashicorpHelpers.createLoadedHashicorpVault(false); 39 | } 40 | 41 | @Test 42 | void hashicorpSignerIsCreatedAndExpectedAddressIsReported(@TempDir final Path tempDir) { 43 | createHashicorpTomlFileAt(tempDir.resolve(PUBLIC_KEY_HEX_STRING + ".toml"), hashicorpNode); 44 | setup(tempDir); 45 | 46 | assertThat( 47 | signerProvider.availablePublicKeys(PublicKeySignerIdentifier::new).stream() 48 | .map(EthPublicKeyUtils::toHexString)) 49 | .containsOnly("0x" + PUBLIC_KEY_HEX_STRING); 50 | } 51 | 52 | @AfterAll 53 | static void tearDown() { 54 | hashicorpNode.shutdown(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /acceptance-tests/src/test/java/tech/pegasys/signers/secp256k1/tests/multikey/HashicorpHelpers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.tests.multikey; 14 | 15 | import static java.util.Collections.singletonMap; 16 | 17 | import tech.pegasys.signers.hashicorp.dsl.HashicorpNode; 18 | import tech.pegasys.signers.secp256k1.HashicorpSigningParams; 19 | 20 | public class HashicorpHelpers { 21 | 22 | public static final String secretPath = "acceptanceTestSecretPath"; 23 | public static final String secretName = "value"; 24 | private static final String PRIVATE_KEY_HEX_STRING = 25 | "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63"; 26 | 27 | public static HashicorpSigningParams createLoadedHashicorpVault(boolean useTls) { 28 | final HashicorpNode hashicorpNode = HashicorpNode.createAndStartHashicorp(useTls); 29 | hashicorpNode.addSecretsToVault(singletonMap(secretName, PRIVATE_KEY_HEX_STRING), secretPath); 30 | 31 | return new HashicorpSigningParams(hashicorpNode, secretPath, secretName); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /acceptance-tests/src/test/java/tech/pegasys/signers/secp256k1/tests/multikey/HashicorpTlsBasedTomlLoadingAcceptanceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.tests.multikey; 14 | 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | import static tech.pegasys.signers.secp256k1.MultiKeyTomlFileUtil.createHashicorpTomlFileAt; 17 | 18 | import tech.pegasys.signers.secp256k1.EthPublicKeyUtils; 19 | import tech.pegasys.signers.secp256k1.HashicorpSigningParams; 20 | import tech.pegasys.signers.secp256k1.common.PublicKeySignerIdentifier; 21 | 22 | import java.nio.file.Path; 23 | import java.util.stream.Collectors; 24 | 25 | import org.junit.jupiter.api.AfterAll; 26 | import org.junit.jupiter.api.BeforeAll; 27 | import org.junit.jupiter.api.Test; 28 | import org.junit.jupiter.api.io.TempDir; 29 | import org.web3j.utils.Numeric; 30 | 31 | class HashicorpTlsBasedTomlLoadingAcceptanceTest extends MultiKeyAcceptanceTestBase { 32 | 33 | public static final String PUBLIC_KEY_HEX_STRING = 34 | "09b02f8a5fddd222ade4ea4528faefc399623af3f736be3c44f03e2df22fb792f3931a4d9573d333ca74343305762a753388c3422a86d98b713fc91c1ea04842"; 35 | 36 | private static HashicorpSigningParams hashicorpNode; 37 | 38 | @BeforeAll 39 | static void setUpBase() { 40 | hashicorpNode = HashicorpHelpers.createLoadedHashicorpVault(true); 41 | } 42 | 43 | @Test 44 | void hashicorpSignerIsCreatedAndExpectedAddressIsReported(@TempDir final Path tempDir) { 45 | createHashicorpTomlFileAt(tempDir.resolve(PUBLIC_KEY_HEX_STRING + ".toml"), hashicorpNode); 46 | setup(tempDir); 47 | assertThat( 48 | signerProvider.availablePublicKeys(PublicKeySignerIdentifier::new).stream() 49 | .map(EthPublicKeyUtils::toByteArray) 50 | .collect(Collectors.toList())) 51 | .containsOnly(Numeric.hexStringToByteArray(PUBLIC_KEY_HEX_STRING)); 52 | } 53 | 54 | @AfterAll 55 | static void tearDown() { 56 | hashicorpNode.shutdown(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /acceptance-tests/src/test/java/tech/pegasys/signers/secp256k1/tests/multikey/MultiKeyAcceptanceTestBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.tests.multikey; 14 | 15 | import tech.pegasys.signers.secp256k1.AllTomlConfigFilesSelector; 16 | import tech.pegasys.signers.secp256k1.SignerIdentifierConfigFileSelector; 17 | import tech.pegasys.signers.secp256k1.multikey.MultiKeySignerProvider; 18 | 19 | import java.nio.file.Path; 20 | 21 | public class MultiKeyAcceptanceTestBase { 22 | 23 | protected MultiKeySignerProvider signerProvider; 24 | 25 | protected void setup(final Path tomlDirectory) { 26 | this.signerProvider = 27 | MultiKeySignerProvider.create( 28 | tomlDirectory, 29 | new AllTomlConfigFilesSelector(), 30 | new SignerIdentifierConfigFileSelector()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /acceptance-tests/src/test/java/tech/pegasys/signers/secp256k1/tests/multikey/signing/MultiKeyAzureTransactionSignerAcceptanceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.tests.multikey.signing; 14 | 15 | import static tech.pegasys.signers.secp256k1.MultiKeyTomlFileUtil.createAzureTomlFileAt; 16 | 17 | import java.nio.file.Path; 18 | 19 | import org.junit.jupiter.api.Assumptions; 20 | import org.junit.jupiter.api.BeforeAll; 21 | import org.junit.jupiter.api.Test; 22 | import org.junit.jupiter.api.io.TempDir; 23 | 24 | public class MultiKeyAzureTransactionSignerAcceptanceTest 25 | extends MultiKeyTransactionSigningAcceptanceTestBase { 26 | 27 | static final String clientId = System.getenv("AZURE_CLIENT_ID"); 28 | static final String clientSecret = System.getenv("AZURE_CLIENT_SECRET"); 29 | static final String keyVaultName = System.getenv("AZURE_KEY_VAULT_NAME"); 30 | static final String tenantId = System.getenv("AZURE_TENANT_ID"); 31 | private static final String AZURE_PUBLIC_KEY_HEX_STRING = 32 | "964f00253459f1f43c7a7720a0db09a328d4ee6f18838015023135d7fc921f1448de34d05de7a1f72a7b5c9f6c76931d7ab33d0f0846ccce5452063bd20f5809"; 33 | 34 | @BeforeAll 35 | static void preChecks() { 36 | Assumptions.assumeTrue( 37 | clientId != null && clientSecret != null && keyVaultName != null && tenantId != null, 38 | "Ensure Azure env variables are set"); 39 | } 40 | 41 | @Test 42 | public void azureLoadedFromMultiKeyCanSign(@TempDir Path tomlDirectory) { 43 | createAzureTomlFileAt( 44 | tomlDirectory.resolve(AZURE_PUBLIC_KEY_HEX_STRING + ".toml"), 45 | clientId, 46 | clientSecret, 47 | keyVaultName, 48 | tenantId); 49 | setup(tomlDirectory); 50 | verifySignature(AZURE_PUBLIC_KEY_HEX_STRING); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /acceptance-tests/src/test/java/tech/pegasys/signers/secp256k1/tests/multikey/signing/MultiKeyFileBasedTransactionSignerAcceptanceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.tests.multikey.signing; 14 | 15 | import static java.nio.charset.StandardCharsets.UTF_8; 16 | import static tech.pegasys.signers.secp256k1.MultiKeyTomlFileUtil.createFileBasedTomlFileAt; 17 | 18 | import java.io.File; 19 | import java.io.IOException; 20 | import java.net.URISyntaxException; 21 | import java.nio.file.Files; 22 | import java.nio.file.Path; 23 | 24 | import com.google.common.io.Resources; 25 | import org.junit.jupiter.api.Test; 26 | import org.junit.jupiter.api.io.TempDir; 27 | 28 | public class MultiKeyFileBasedTransactionSignerAcceptanceTest 29 | extends MultiKeyTransactionSigningAcceptanceTestBase { 30 | 31 | static final String FILENAME = 32 | "09b02f8a5fddd222ade4ea4528faefc399623af3f736be3c44f03e2df22fb792f3931a4d9573d333ca74343305762a753388c3422a86d98b713fc91c1ea04842"; 33 | 34 | @Test 35 | public void fileBasedMultiKeyCanSign(@TempDir Path tomlDirectory) 36 | throws URISyntaxException, IOException { 37 | final String keyPath = 38 | new File(Resources.getResource("secp256k1/rich_benefactor_one.json").toURI()) 39 | .getAbsolutePath(); 40 | 41 | final Path passwordPath = tomlDirectory.resolve("password"); 42 | Files.write(passwordPath, "pass".getBytes(UTF_8)); 43 | 44 | createFileBasedTomlFileAt( 45 | tomlDirectory.resolve(FILENAME + ".toml"), keyPath, passwordPath.toString()); 46 | 47 | setup(tomlDirectory); 48 | verifySignature(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /acceptance-tests/src/test/java/tech/pegasys/signers/secp256k1/tests/multikey/signing/MultiKeyHashicorpTransactionSignerAcceptanceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.tests.multikey.signing; 14 | 15 | import static tech.pegasys.signers.secp256k1.MultiKeyTomlFileUtil.createHashicorpTomlFileAt; 16 | 17 | import tech.pegasys.signers.secp256k1.HashicorpSigningParams; 18 | import tech.pegasys.signers.secp256k1.tests.multikey.HashicorpHelpers; 19 | 20 | import java.nio.file.Path; 21 | 22 | import org.junit.jupiter.api.AfterAll; 23 | import org.junit.jupiter.api.BeforeAll; 24 | import org.junit.jupiter.api.Test; 25 | import org.junit.jupiter.api.io.TempDir; 26 | 27 | public class MultiKeyHashicorpTransactionSignerAcceptanceTest 28 | extends MultiKeyTransactionSigningAcceptanceTestBase { 29 | 30 | static final String FILENAME = 31 | "09b02f8a5fddd222ade4ea4528faefc399623af3f736be3c44f03e2df22fb792f3931a4d9573d333ca74343305762a753388c3422a86d98b713fc91c1ea04842"; 32 | 33 | private static HashicorpSigningParams hashicorpNode; 34 | 35 | @BeforeAll 36 | static void preSetup() { 37 | hashicorpNode = HashicorpHelpers.createLoadedHashicorpVault(false); 38 | } 39 | 40 | @Test 41 | void hashicorpLoadedFromMultiKeyCanSign(@TempDir Path tomlDirectory) { 42 | 43 | createHashicorpTomlFileAt(tomlDirectory.resolve(FILENAME + ".toml"), hashicorpNode); 44 | 45 | setup(tomlDirectory); 46 | verifySignature(); 47 | } 48 | 49 | @AfterAll 50 | static void tearDown() { 51 | if (hashicorpNode != null) { 52 | hashicorpNode.shutdown(); 53 | hashicorpNode = null; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /acceptance-tests/src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | INFO 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /acceptance-tests/src/test/resources/secp256k1/UTC--2019-12-05T05-17-11.151993000Z--a01f618424b0113a9cebdc6cb66ca5b48e9120c5.key: -------------------------------------------------------------------------------- 1 | {"address":"a01f618424b0113a9cebdc6cb66ca5b48e9120c5","id":"f09c781e-a107-4e07-9079-dd755ae2267a","version":3,"crypto":{"cipher":"aes-128-ctr","ciphertext":"e577be9f433e07eb8109348eca7a971631294f984525feb4d859b5dd0dc9f17e","cipherparams":{"iv":"654ef2dd48f71afa05ccca86553c9d66"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"0f91375b7dd73aa8fd59c6dade111747eb1b1395f954e980ef7ef9d0632358a9"},"mac":"2e732f4d299100ce3df72e9b9c204f90c49f7b59996b271393e85a6dc26cf883"}} -------------------------------------------------------------------------------- /acceptance-tests/src/test/resources/secp256k1/UTC--2019-12-05T05-17-11.151993000Z--a01f618424b0113a9cebdc6cb66ca5b48e9120c5.password: -------------------------------------------------------------------------------- 1 | password -------------------------------------------------------------------------------- /acceptance-tests/src/test/resources/secp256k1/rich_benefactor_one.json: -------------------------------------------------------------------------------- 1 | {"address":"fe3b557e8fb62b89f4916b721be55ceb828dbd73","crypto":{"cipher":"aes-128-ctr","ciphertext":"c330870080626a6cf84c36eeb89f6376316637fbc16c86400eb6c394de5aed81","cipherparams":{"iv":"7f2526feb38ac355c644a84e78ec5692"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"b0da609bb541df918eb55bbeaf237445aa406a0c2d6e975663c4fcb221bc54e0"},"mac":"1ed0ef9e2092d0f5db8d16409ee2aaee9af3f521a5eafd910ce19dbc76e67ed7"},"id":"43f8e00a-c6ec-4a62-b7cb-f54cb299c3db","version":3} -------------------------------------------------------------------------------- /acceptance-tests/src/testFixtures/java/tech.pegasys.signers.secp256k1/AllTomlConfigFilesSelector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1; 14 | 15 | import tech.pegasys.signers.secp256k1.api.FileSelector; 16 | 17 | import java.nio.file.DirectoryStream; 18 | import java.nio.file.Path; 19 | 20 | public class AllTomlConfigFilesSelector implements FileSelector { 21 | @Override 22 | public DirectoryStream.Filter getConfigFilesFilter(final Void selectionCriteria) { 23 | return entry -> entry.getFileName().toString().endsWith("toml"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /acceptance-tests/src/testFixtures/java/tech.pegasys.signers.secp256k1/HashicorpSigningParams.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1; 14 | 15 | import tech.pegasys.signers.hashicorp.dsl.HashicorpNode; 16 | import tech.pegasys.signers.hashicorp.dsl.certificates.SelfSignedCertificate; 17 | 18 | import java.util.Optional; 19 | 20 | public class HashicorpSigningParams { 21 | 22 | final HashicorpNode hashicorpNode; 23 | final String secretPath; 24 | final String secretName; 25 | 26 | public HashicorpSigningParams( 27 | final HashicorpNode hashicorpNode, final String secretPath, final String secretName) { 28 | this.hashicorpNode = hashicorpNode; 29 | this.secretPath = secretPath; 30 | this.secretName = secretName; 31 | } 32 | 33 | public int getPort() { 34 | return hashicorpNode.getPort(); 35 | } 36 | 37 | public String getHost() { 38 | return hashicorpNode.getHost(); 39 | } 40 | 41 | public String getVaultToken() { 42 | return hashicorpNode.getVaultToken(); 43 | } 44 | 45 | public Optional getServerCertificate() { 46 | return hashicorpNode.getServerCertificate(); 47 | } 48 | 49 | public String getSecretHttpPath() { 50 | return hashicorpNode.getHttpApiPathForSecret(secretPath); 51 | } 52 | 53 | public String getSecretName() { 54 | return secretName; 55 | } 56 | 57 | public void shutdown() { 58 | hashicorpNode.shutdown(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /acceptance-tests/src/testFixtures/java/tech.pegasys.signers.secp256k1/SignerIdentifierConfigFileSelector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1; 14 | 15 | import tech.pegasys.signers.secp256k1.api.FileSelector; 16 | import tech.pegasys.signers.secp256k1.api.SignerIdentifier; 17 | 18 | import java.nio.file.DirectoryStream; 19 | import java.nio.file.Path; 20 | 21 | public class SignerIdentifierConfigFileSelector implements FileSelector { 22 | 23 | @Override 24 | public DirectoryStream.Filter getConfigFilesFilter( 25 | final SignerIdentifier signerIdentifier) { 26 | return entry -> 27 | entry.getFileName().toString().equals(signerIdentifier.toStringIdentifier() + ".toml"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /bls-keystore/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | 14 | apply plugin: 'java-library' 15 | 16 | jar { 17 | archiveBaseName = "bls-keystore" 18 | manifest { 19 | attributes( 20 | 'Specification-Title': archiveBaseName.get(), 21 | 'Specification-Version': rootProject.version, 22 | 'Implementation-Title': archiveBaseName.get(), 23 | 'Implementation-Version': calculateVersion() 24 | ) 25 | } 26 | } 27 | 28 | dependencies { 29 | implementation 'com.fasterxml.jackson.core:jackson-databind' 30 | implementation 'org.bouncycastle:bcprov-jdk15on' 31 | implementation 'com.google.guava:guava' 32 | implementation 'org.apache.logging.log4j:log4j-api' 33 | implementation 'org.apache.tuweni:tuweni-bytes' 34 | implementation 'org.apache.tuweni:tuweni-crypto' 35 | 36 | testImplementation 'org.assertj:assertj-core' 37 | testImplementation 'org.junit.jupiter:junit-jupiter-engine' 38 | testImplementation 'org.junit.jupiter:junit-jupiter-api' 39 | testImplementation 'org.junit.jupiter:junit-jupiter-params' 40 | testImplementation 'org.mockito:mockito-core' 41 | testImplementation 'org.mockito:mockito-junit-jupiter' 42 | } 43 | -------------------------------------------------------------------------------- /bls-keystore/src/main/java/tech/pegasys/signers/bls/keystore/KeyStoreValidationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore; 14 | 15 | public class KeyStoreValidationException extends RuntimeException { 16 | public KeyStoreValidationException() { 17 | super(); 18 | } 19 | 20 | public KeyStoreValidationException(final String message) { 21 | super(message); 22 | } 23 | 24 | public KeyStoreValidationException(final String message, final Throwable cause) { 25 | super(message, cause); 26 | } 27 | 28 | public KeyStoreValidationException(final Throwable cause) { 29 | super(cause); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bls-keystore/src/main/java/tech/pegasys/signers/bls/keystore/PasswordUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore; 14 | 15 | import static java.nio.charset.StandardCharsets.UTF_8; 16 | 17 | import java.text.Normalizer; 18 | import java.text.Normalizer.Form; 19 | 20 | import org.apache.tuweni.bytes.Bytes; 21 | 22 | public class PasswordUtils { 23 | 24 | public static Bytes normalizePassword(final String password) { 25 | final String normalizedPassword = Normalizer.normalize(password, Form.NFKD); 26 | final int[] filteredCodepoints = 27 | normalizedPassword.chars().filter(c -> !isControlCode(c)).toArray(); 28 | final byte[] utf8Password = 29 | new String(filteredCodepoints, 0, filteredCodepoints.length).getBytes(UTF_8); 30 | return Bytes.wrap(utf8Password); 31 | } 32 | 33 | private static boolean isControlCode(final int c) { 34 | return isC0(c) || isC1(c) || c == 0x7F; 35 | } 36 | 37 | private static boolean isC1(final int c) { 38 | return 0x80 <= c && c <= 0x9F; 39 | } 40 | 41 | private static boolean isC0(final int c) { 42 | return 0x00 <= c && c <= 0x1F; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /bls-keystore/src/main/java/tech/pegasys/signers/bls/keystore/model/Checksum.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore.model; 14 | 15 | import com.fasterxml.jackson.annotation.JsonCreator; 16 | import com.fasterxml.jackson.annotation.JsonProperty; 17 | import com.google.common.base.MoreObjects; 18 | import org.apache.tuweni.bytes.Bytes; 19 | 20 | public class Checksum { 21 | private final ChecksumFunction checksumFunction; 22 | private final EmptyParam emptyParam; 23 | private final Bytes message; 24 | 25 | @JsonCreator 26 | public Checksum( 27 | @JsonProperty(value = "function", required = true) final ChecksumFunction checksumFunction, 28 | @JsonProperty(value = "params", required = true) final EmptyParam emptyParam, 29 | @JsonProperty(value = "message", required = true) final Bytes message) { 30 | this.checksumFunction = checksumFunction; 31 | this.emptyParam = emptyParam; 32 | this.message = message; 33 | } 34 | 35 | public Checksum(final Bytes message) { 36 | this(ChecksumFunction.SHA256, new EmptyParam(), message); 37 | } 38 | 39 | @JsonProperty(value = "function") 40 | public ChecksumFunction getChecksumFunction() { 41 | return checksumFunction; 42 | } 43 | 44 | @JsonProperty(value = "params") 45 | public EmptyParam getEmptyParam() { 46 | return emptyParam; 47 | } 48 | 49 | @JsonProperty(value = "message") 50 | public Bytes getMessage() { 51 | return message; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return MoreObjects.toStringHelper(this) 57 | .add("function", checksumFunction) 58 | .add("param", emptyParam) 59 | .add("message", message) 60 | .toString(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /bls-keystore/src/main/java/tech/pegasys/signers/bls/keystore/model/ChecksumFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore.model; 14 | 15 | import com.fasterxml.jackson.annotation.JsonValue; 16 | 17 | public enum ChecksumFunction { 18 | SHA256("sha256"); 19 | private final String jsonValue; 20 | 21 | ChecksumFunction(final String jsonValue) { 22 | this.jsonValue = jsonValue; 23 | } 24 | 25 | @JsonValue 26 | public String getJsonValue() { 27 | return this.jsonValue; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /bls-keystore/src/main/java/tech/pegasys/signers/bls/keystore/model/Cipher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore.model; 14 | 15 | import tech.pegasys.signers.bls.keystore.KeyStoreValidationException; 16 | 17 | import com.fasterxml.jackson.annotation.JsonCreator; 18 | import com.fasterxml.jackson.annotation.JsonProperty; 19 | import com.google.common.base.MoreObjects; 20 | import org.apache.tuweni.bytes.Bytes; 21 | 22 | public class Cipher { 23 | private final CipherFunction cipherFunction; 24 | private final CipherParam cipherParam; 25 | private final Bytes message; 26 | 27 | @JsonCreator 28 | public Cipher( 29 | @JsonProperty(value = "function", required = true) final CipherFunction cipherFunction, 30 | @JsonProperty(value = "params", required = true) final CipherParam cipherParam, 31 | @JsonProperty(value = "message", required = true) final Bytes message) { 32 | this.cipherFunction = cipherFunction; 33 | this.cipherParam = cipherParam; 34 | this.message = message; 35 | } 36 | 37 | public Cipher(final CipherFunction cipherFunction, final Bytes ivParam) { 38 | this(cipherFunction, new CipherParam(ivParam), Bytes.EMPTY); 39 | } 40 | 41 | public Cipher(final Bytes ivParam) { 42 | this(CipherFunction.AES_128_CTR, new CipherParam(ivParam), Bytes.EMPTY); 43 | } 44 | 45 | @JsonProperty(value = "function") 46 | public CipherFunction getCipherFunction() { 47 | return cipherFunction; 48 | } 49 | 50 | @JsonProperty(value = "params") 51 | public CipherParam getCipherParam() { 52 | return cipherParam; 53 | } 54 | 55 | @JsonProperty(value = "message") 56 | public Bytes getMessage() { 57 | return message; 58 | } 59 | 60 | public void validate() throws KeyStoreValidationException { 61 | // In case of CTR/SIC, the size of IV is between 8 bytes and 16 bytes 62 | if (cipherParam.getIv().size() < 8 || cipherParam.getIv().size() > 16) { 63 | throw new KeyStoreValidationException( 64 | "Initialization Vector parameter iv size must be >= 8 and <= 16"); 65 | } 66 | } 67 | 68 | @Override 69 | public String toString() { 70 | return MoreObjects.toStringHelper(this) 71 | .add("function", cipherFunction) 72 | .add("params", cipherParam) 73 | .add("message", message) 74 | .toString(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /bls-keystore/src/main/java/tech/pegasys/signers/bls/keystore/model/CipherFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore.model; 14 | 15 | import com.fasterxml.jackson.annotation.JsonValue; 16 | 17 | public enum CipherFunction { 18 | AES_128_CTR("aes-128-ctr"); 19 | 20 | private final String jsonValue; 21 | 22 | CipherFunction(final String jsonValue) { 23 | this.jsonValue = jsonValue; 24 | } 25 | 26 | @JsonValue 27 | public String getJsonValue() { 28 | return this.jsonValue; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /bls-keystore/src/main/java/tech/pegasys/signers/bls/keystore/model/CipherParam.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore.model; 14 | 15 | import com.fasterxml.jackson.annotation.JsonCreator; 16 | import com.fasterxml.jackson.annotation.JsonProperty; 17 | import com.google.common.base.MoreObjects; 18 | import org.apache.tuweni.bytes.Bytes; 19 | 20 | public class CipherParam { 21 | private final Bytes iv; 22 | 23 | @JsonCreator 24 | public CipherParam(@JsonProperty(value = "iv", required = true) final Bytes iv) { 25 | this.iv = iv; 26 | } 27 | 28 | @JsonProperty(value = "iv") 29 | public Bytes getIv() { 30 | return iv; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return MoreObjects.toStringHelper(this).add("iv", iv).toString(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /bls-keystore/src/main/java/tech/pegasys/signers/bls/keystore/model/Crypto.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore.model; 14 | 15 | import com.fasterxml.jackson.annotation.JsonCreator; 16 | import com.fasterxml.jackson.annotation.JsonProperty; 17 | import com.google.common.base.MoreObjects; 18 | 19 | public class Crypto { 20 | private final Kdf kdf; 21 | private final Checksum checksum; 22 | private final Cipher cipher; 23 | 24 | @JsonCreator 25 | public Crypto( 26 | @JsonProperty(value = "kdf", required = true) final Kdf kdf, 27 | @JsonProperty(value = "checksum", required = true) final Checksum checksum, 28 | @JsonProperty(value = "cipher", required = true) final Cipher cipher) { 29 | this.kdf = kdf; 30 | this.checksum = checksum; 31 | this.cipher = cipher; 32 | } 33 | 34 | @JsonProperty(value = "kdf") 35 | public Kdf getKdf() { 36 | return kdf; 37 | } 38 | 39 | @JsonProperty(value = "checksum") 40 | public Checksum getChecksum() { 41 | return checksum; 42 | } 43 | 44 | @JsonProperty(value = "cipher") 45 | public Cipher getCipher() { 46 | return cipher; 47 | } 48 | 49 | public void validate() { 50 | kdf.validate(); 51 | cipher.validate(); 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return MoreObjects.toStringHelper(this) 57 | .add("kdf", kdf) 58 | .add("checksum", checksum) 59 | .add("cipher", cipher) 60 | .toString(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /bls-keystore/src/main/java/tech/pegasys/signers/bls/keystore/model/EmptyParam.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore.model; 14 | 15 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 16 | 17 | /** Placeholder for empty params */ 18 | @JsonIgnoreProperties(ignoreUnknown = true) 19 | public class EmptyParam { 20 | public EmptyParam() {} 21 | 22 | @Override 23 | public String toString() { 24 | return ""; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bls-keystore/src/main/java/tech/pegasys/signers/bls/keystore/model/Kdf.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore.model; 14 | 15 | import tech.pegasys.signers.bls.keystore.KeyStoreValidationException; 16 | 17 | import com.fasterxml.jackson.annotation.JsonCreator; 18 | import com.fasterxml.jackson.annotation.JsonProperty; 19 | import com.fasterxml.jackson.annotation.JsonSubTypes; 20 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 21 | import com.google.common.base.MoreObjects; 22 | 23 | public class Kdf { 24 | private final KdfFunction kdfFunction; 25 | private final KdfParam param; 26 | private final String message; 27 | 28 | @JsonCreator 29 | public Kdf( 30 | @JsonProperty(value = "function", required = true) final KdfFunction kdfFunction, 31 | @JsonProperty(value = "params", required = true) 32 | @JsonTypeInfo( 33 | use = JsonTypeInfo.Id.NAME, 34 | include = JsonTypeInfo.As.EXTERNAL_PROPERTY, 35 | property = "function") 36 | @JsonSubTypes({ 37 | @JsonSubTypes.Type(value = SCryptParam.class, name = "scrypt"), 38 | @JsonSubTypes.Type(value = Pbkdf2Param.class, name = "pbkdf2") 39 | }) 40 | final KdfParam param, 41 | @JsonProperty(value = "message", required = true) final String message) { 42 | this.kdfFunction = kdfFunction; 43 | this.param = param; 44 | this.message = message; 45 | } 46 | 47 | public Kdf(final KdfParam kdfParam) { 48 | this(kdfParam.getKdfFunction(), kdfParam, ""); 49 | } 50 | 51 | @JsonProperty(value = "function") 52 | public KdfFunction getKdfFunction() { 53 | return kdfFunction; 54 | } 55 | 56 | @JsonProperty(value = "params") 57 | public KdfParam getParam() { 58 | return param; 59 | } 60 | 61 | @JsonProperty(value = "message") 62 | public String getMessage() { 63 | return message; 64 | } 65 | 66 | public void validate() throws KeyStoreValidationException { 67 | param.validate(); 68 | } 69 | 70 | @Override 71 | public String toString() { 72 | return MoreObjects.toStringHelper(this) 73 | .add("function", kdfFunction) 74 | .add("params", param) 75 | .add("message", message) 76 | .toString(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /bls-keystore/src/main/java/tech/pegasys/signers/bls/keystore/model/KdfFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore.model; 14 | 15 | import com.fasterxml.jackson.annotation.JsonValue; 16 | 17 | public enum KdfFunction { 18 | PBKDF2("pbkdf2"), 19 | SCRYPT("scrypt"); 20 | 21 | private final String jsonValue; 22 | 23 | KdfFunction(final String jsonValue) { 24 | this.jsonValue = jsonValue; 25 | } 26 | 27 | @JsonValue 28 | public String getJsonValue() { 29 | return this.jsonValue; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bls-keystore/src/main/java/tech/pegasys/signers/bls/keystore/model/KdfParam.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore.model; 14 | 15 | import static com.google.common.base.Preconditions.checkNotNull; 16 | 17 | import tech.pegasys.signers.bls.keystore.KeyStoreValidationException; 18 | import tech.pegasys.signers.bls.keystore.PasswordUtils; 19 | 20 | import com.fasterxml.jackson.annotation.JsonProperty; 21 | import com.google.common.base.MoreObjects; 22 | import org.apache.tuweni.bytes.Bytes; 23 | 24 | public abstract class KdfParam { 25 | private final Integer dklen; 26 | private final Bytes salt; 27 | 28 | public KdfParam(final Integer dklen, final Bytes salt) { 29 | this.dklen = dklen; 30 | this.salt = salt; 31 | } 32 | 33 | @JsonProperty(value = "dklen") 34 | public Integer getDkLen() { 35 | return dklen; 36 | } 37 | 38 | public abstract KdfFunction getKdfFunction(); 39 | 40 | public Bytes generateDecryptionKey(final String password) { 41 | return generateDecryptionKey(PasswordUtils.normalizePassword(password)); 42 | } 43 | 44 | protected abstract Bytes generateDecryptionKey(final Bytes password); 45 | 46 | public void validate() { 47 | checkNotNull(getSalt(), "salt cannot be null"); 48 | // because the EIP-2335 spec requires dklen >= 32 49 | if (dklen < 32) { 50 | throw new KeyStoreValidationException("Generated key length parameter dklen must be >= 32."); 51 | } 52 | } 53 | 54 | @JsonProperty(value = "salt") 55 | public Bytes getSalt() { 56 | return salt; 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | return MoreObjects.toStringHelper(this).add("dklen", dklen).add("salt", salt).toString(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /bls-keystore/src/main/java/tech/pegasys/signers/bls/keystore/model/Pbkdf2PseudoRandomFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore.model; 14 | 15 | import com.fasterxml.jackson.annotation.JsonValue; 16 | 17 | public enum Pbkdf2PseudoRandomFunction { 18 | HMAC_SHA256("hmac-sha256"); 19 | private final String jsonValue; 20 | 21 | Pbkdf2PseudoRandomFunction(final String jsonValue) { 22 | this.jsonValue = jsonValue; 23 | } 24 | 25 | @JsonValue 26 | public String getJsonValue() { 27 | return this.jsonValue; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /bls-keystore/src/test/java/tech/pegasys/signers/bls/keystore/DecryptionKeyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore; 14 | 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | 17 | import tech.pegasys.signers.bls.keystore.model.Pbkdf2Param; 18 | import tech.pegasys.signers.bls.keystore.model.Pbkdf2PseudoRandomFunction; 19 | import tech.pegasys.signers.bls.keystore.model.SCryptParam; 20 | 21 | import org.apache.tuweni.bytes.Bytes; 22 | import org.junit.jupiter.api.Test; 23 | 24 | class DecryptionKeyTest { 25 | private static final int DKLEN = 32; 26 | private static final int ITERATIVE_COUNT = 262144; 27 | private static final int MEMORY_CPU_COST = 262144; 28 | private static final int PARALLELIZATION = 1; 29 | private static final int BLOCKSIZE = 8; 30 | private static final Bytes SALT = 31 | Bytes.fromHexString("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"); 32 | private static final Bytes SCRYPT_DERIVED_KEY = 33 | Bytes.fromHexString("0xBC21AF552ED055E3B3F35A39AFD8355903CA2770709B5E5B363647FA75234344"); 34 | private static final Bytes PBKDF2_DERIVED_KEY = 35 | Bytes.fromHexString("0x57E2285C828F4F6B95DEEC3BB6D9D90933042C63FC9BADE14EA280202A17142D"); 36 | private static final String PASSWORD = "testpassword"; 37 | 38 | @Test 39 | void sCryptDecryptionKeyGeneration() { 40 | final SCryptParam kdfParam = 41 | new SCryptParam(DKLEN, MEMORY_CPU_COST, PARALLELIZATION, BLOCKSIZE, SALT); 42 | final Bytes decryptionKey = kdfParam.generateDecryptionKey(PASSWORD); 43 | assertThat(decryptionKey.size()).isEqualTo(DKLEN); 44 | assertThat(decryptionKey).isEqualTo(SCRYPT_DERIVED_KEY); 45 | } 46 | 47 | @Test 48 | void pbkdf2DecryptionKeyGeneration() { 49 | final Pbkdf2Param kdfParam = 50 | new Pbkdf2Param(DKLEN, ITERATIVE_COUNT, Pbkdf2PseudoRandomFunction.HMAC_SHA256, SALT); 51 | final Bytes decryptionKey = kdfParam.generateDecryptionKey(PASSWORD); 52 | assertThat(decryptionKey.size()).isEqualTo(DKLEN); 53 | assertThat(decryptionKey).isEqualTo(PBKDF2_DERIVED_KEY); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /bls-keystore/src/test/java/tech/pegasys/signers/bls/keystore/PasswordUtilsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore; 14 | 15 | import static java.nio.charset.StandardCharsets.UTF_8; 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | import static tech.pegasys.signers.bls.keystore.PasswordUtils.normalizePassword; 18 | 19 | import org.apache.tuweni.bytes.Bytes; 20 | import org.junit.jupiter.api.Test; 21 | 22 | class PasswordUtilsTest { 23 | @Test 24 | void shouldLeaveSimplePasswordUnchanged() { 25 | assertThat(normalizePassword("testpassword")).isEqualTo(utf8("testpassword")); 26 | } 27 | 28 | @Test 29 | void shouldStripControlCharactersFromPassword() { 30 | assertThat(normalizePassword("\u0000\u001F\u0080\u009Ftest \n\f\tpass\u007Fword\n")) 31 | .isEqualTo(utf8("test password")); 32 | } 33 | 34 | @Test 35 | void shouldDecodePasswordFromEip2335() { 36 | final String password = 37 | "\uD835\uDD31\uD835\uDD22\uD835\uDD30\uD835\uDD31\uD835\uDD2D\uD835\uDD1E\uD835\uDD30\uD835\uDD30\uD835\uDD34\uD835\uDD2C\uD835\uDD2F\uD835\uDD21\uD83D\uDD11"; 38 | assertThat(normalizePassword(password)) 39 | .isEqualTo(Bytes.fromHexString("0x7465737470617373776f7264f09f9491")); 40 | } 41 | 42 | private Bytes utf8(final String password) { 43 | return Bytes.wrap(password.getBytes(UTF_8)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /bls-keystore/src/test/java/tech/pegasys/signers/bls/keystore/model/CipherTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.bls.keystore.model; 14 | 15 | import static org.assertj.core.api.Assertions.assertThatCode; 16 | import static org.assertj.core.api.Assertions.assertThatExceptionOfType; 17 | 18 | import tech.pegasys.signers.bls.keystore.KeyStoreValidationException; 19 | 20 | import org.apache.tuweni.bytes.Bytes; 21 | import org.junit.jupiter.params.ParameterizedTest; 22 | import org.junit.jupiter.params.provider.ValueSource; 23 | 24 | class CipherTest { 25 | @ParameterizedTest 26 | @ValueSource(ints = {7, 17}) 27 | void cipherWithInvalidIvLengthThrowsException(final int bytesSize) { 28 | assertThatExceptionOfType(KeyStoreValidationException.class) 29 | .isThrownBy(new Cipher(Bytes.random(bytesSize))::validate) 30 | .withMessage("Initialization Vector parameter iv size must be >= 8 and <= 16"); 31 | } 32 | 33 | @ParameterizedTest 34 | @ValueSource(ints = {8, 16}) 35 | void cipherWithValidIvLengthValidateDoesNotThrowException(final int bytesSize) { 36 | assertThatCode(new Cipher(Bytes.random(bytesSize))::validate).doesNotThrowAnyException(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /bls-keystore/src/test/resources/missingKdfSectionTestVector.json: -------------------------------------------------------------------------------- 1 | { 2 | "crypto": { 3 | "kdf": { 4 | "function": "scrypt", 5 | "message": "" 6 | }, 7 | "checksum": { 8 | "function": "sha256", 9 | "params": {}, 10 | "message": "149aafa27b041f3523c53d7acba1905fa6b1c90f9fef137568101f44b531a3cb" 11 | }, 12 | "cipher": { 13 | "function": "aes-128-ctr", 14 | "params": { 15 | "iv": "264daa3f303d7259501c93d997d84fe6" 16 | }, 17 | "message": "54ecc8863c0550351eee5720f3be6a5d4a016025aa91cd6436cfec938d6a8d30" 18 | } 19 | }, 20 | "pubkey": "9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07", 21 | "path": "m/12381/60/3141592653/589793238", 22 | "uuid": "1d85ae20-35c5-4611-98e8-aa14a633906f", 23 | "version": 4 24 | } -------------------------------------------------------------------------------- /bls-keystore/src/test/resources/pbkdf2TestVector.json: -------------------------------------------------------------------------------- 1 | { 2 | "crypto": { 3 | "kdf": { 4 | "function": "pbkdf2", 5 | "params": { 6 | "dklen": 32, 7 | "c": 262144, 8 | "prf": "hmac-sha256", 9 | "salt": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" 10 | }, 11 | "message": "" 12 | }, 13 | "checksum": { 14 | "function": "sha256", 15 | "params": {}, 16 | "message": "8a9f5d9912ed7e75ea794bc5a89bca5f193721d30868ade6f73043c6ea6febf1" 17 | }, 18 | "cipher": { 19 | "function": "aes-128-ctr", 20 | "params": { 21 | "iv": "264daa3f303d7259501c93d997d84fe6" 22 | }, 23 | "message": "cee03fde2af33149775b7223e7845e4fb2c8ae1792e5f99fe9ecf474cc8c16ad" 24 | } 25 | }, 26 | "description": "This is a test keystore that uses PBKDF2 to secure the secret.", 27 | "pubkey": "9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07", 28 | "path": "m/12381/60/0/0", 29 | "uuid": "64625def-3331-4eea-ab6f-782f3ed16a83", 30 | "version": 4 31 | } -------------------------------------------------------------------------------- /bls-keystore/src/test/resources/scryptExtraFieldTestVector.json: -------------------------------------------------------------------------------- 1 | { 2 | "crypto": { 3 | "kdf": { 4 | "function": "scrypt", 5 | "params": { 6 | "dklen": 32, 7 | "n": 262144, 8 | "p": 1, 9 | "r": 8, 10 | "salt": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" 11 | }, 12 | "message": "" 13 | }, 14 | "checksum": { 15 | "function": "sha256", 16 | "params": {}, 17 | "message": "d2217fe5f3e9a1e34581ef8a78f7c9928e436d36dacc5e846690a5581e8ea484" 18 | }, 19 | "cipher": { 20 | "function": "aes-128-ctr", 21 | "params": { 22 | "iv": "264daa3f303d7259501c93d997d84fe6" 23 | }, 24 | "message": "06ae90d55fe0a6e9c5c3bc5b170827b2e5cce3929ed3f116c2811e6366dfe20f" 25 | } 26 | }, 27 | "pubkey": "9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07", 28 | "path": "m/12381/60/3141592653/589793238", 29 | "uuid": "1d85ae20-35c5-4611-98e8-aa14a633906f", 30 | "name": "Test", 31 | "version": 4 32 | } -------------------------------------------------------------------------------- /bls-keystore/src/test/resources/scryptTestVector.json: -------------------------------------------------------------------------------- 1 | { 2 | "crypto": { 3 | "kdf": { 4 | "function": "scrypt", 5 | "params": { 6 | "dklen": 32, 7 | "n": 262144, 8 | "p": 1, 9 | "r": 8, 10 | "salt": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" 11 | }, 12 | "message": "" 13 | }, 14 | "checksum": { 15 | "function": "sha256", 16 | "params": {}, 17 | "message": "d2217fe5f3e9a1e34581ef8a78f7c9928e436d36dacc5e846690a5581e8ea484" 18 | }, 19 | "cipher": { 20 | "function": "aes-128-ctr", 21 | "params": { 22 | "iv": "264daa3f303d7259501c93d997d84fe6" 23 | }, 24 | "message": "06ae90d55fe0a6e9c5c3bc5b170827b2e5cce3929ed3f116c2811e6366dfe20f" 25 | } 26 | }, 27 | "description": "This is a test keystore that uses scrypt to secure the secret.", 28 | "pubkey": "9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07", 29 | "path": "m/12381/60/3141592653/589793238", 30 | "uuid": "1d85ae20-35c5-4611-98e8-aa14a633906f", 31 | "version": 4 32 | } -------------------------------------------------------------------------------- /bls-keystore/src/test/resources/scryptTestVectorWithMissingPathAndUUID.json: -------------------------------------------------------------------------------- 1 | { 2 | "crypto": { 3 | "kdf": { 4 | "function": "scrypt", 5 | "params": { 6 | "dklen": 32, 7 | "n": 262144, 8 | "p": 1, 9 | "r": 8, 10 | "salt": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" 11 | }, 12 | "message": "" 13 | }, 14 | "checksum": { 15 | "function": "sha256", 16 | "params": {}, 17 | "message": "d2217fe5f3e9a1e34581ef8a78f7c9928e436d36dacc5e846690a5581e8ea484" 18 | }, 19 | "cipher": { 20 | "function": "aes-128-ctr", 21 | "params": { 22 | "iv": "264daa3f303d7259501c93d997d84fe6" 23 | }, 24 | "message": "06ae90d55fe0a6e9c5c3bc5b170827b2e5cce3929ed3f116c2811e6366dfe20f" 25 | } 26 | }, 27 | "description": "This is a test keystore that uses scrypt to secure the secret.", 28 | "pubkey": "9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07", 29 | "version": 4 30 | } -------------------------------------------------------------------------------- /bls-keystore/src/test/resources/unsupportedChecksumFunction.json: -------------------------------------------------------------------------------- 1 | { 2 | "crypto": { 3 | "kdf": { 4 | "function": "scrypt", 5 | "params": { 6 | "dklen": 32, 7 | "n": 262144, 8 | "p": 1, 9 | "r": 8, 10 | "salt": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" 11 | }, 12 | "message": "" 13 | }, 14 | "checksum": { 15 | "function": "sha128", 16 | "params": {}, 17 | "message": "149aafa27b041f3523c53d7acba1905fa6b1c90f9fef137568101f44b531a3cb" 18 | }, 19 | "cipher": { 20 | "function": "aes-128-ctr", 21 | "params": { 22 | "iv": "264daa3f303d7259501c93d997d84fe6" 23 | }, 24 | "message": "54ecc8863c0550351eee5720f3be6a5d4a016025aa91cd6436cfec938d6a8d30" 25 | } 26 | }, 27 | "pubkey": "9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07", 28 | "path": "m/12381/60/3141592653/589793238", 29 | "uuid": "1d85ae20-35c5-4611-98e8-aa14a633906f", 30 | "version": 4 31 | } -------------------------------------------------------------------------------- /bls-keystore/src/test/resources/unsupportedCipherFunction.json: -------------------------------------------------------------------------------- 1 | { 2 | "crypto": { 3 | "kdf": { 4 | "function": "scrypt", 5 | "params": { 6 | "dklen": 32, 7 | "n": 262144, 8 | "p": 1, 9 | "r": 8, 10 | "salt": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" 11 | }, 12 | "message": "" 13 | }, 14 | "checksum": { 15 | "function": "sha256", 16 | "params": {}, 17 | "message": "149aafa27b041f3523c53d7acba1905fa6b1c90f9fef137568101f44b531a3cb" 18 | }, 19 | "cipher": { 20 | "function": "aes-256-ctr", 21 | "params": { 22 | "iv": "264daa3f303d7259501c93d997d84fe6" 23 | }, 24 | "message": "54ecc8863c0550351eee5720f3be6a5d4a016025aa91cd6436cfec938d6a8d30" 25 | } 26 | }, 27 | "pubkey": "9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07", 28 | "path": "m/12381/60/3141592653/589793238", 29 | "uuid": "1d85ae20-35c5-4611-98e8-aa14a633906f", 30 | "version": 4 31 | } -------------------------------------------------------------------------------- /bls-keystore/src/test/resources/unsupportedDkLen.json: -------------------------------------------------------------------------------- 1 | { 2 | "crypto": { 3 | "kdf": { 4 | "function": "scrypt", 5 | "params": { 6 | "dklen": 31, 7 | "n": 262144, 8 | "p": 1, 9 | "r": 8, 10 | "salt": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" 11 | }, 12 | "message": "" 13 | }, 14 | "checksum": { 15 | "function": "sha256", 16 | "params": {}, 17 | "message": "149aafa27b041f3523c53d7acba1905fa6b1c90f9fef137568101f44b531a3cb" 18 | }, 19 | "cipher": { 20 | "function": "aes-128-ctr", 21 | "params": { 22 | "iv": "264daa3f303d7259501c93d997d84fe6" 23 | }, 24 | "message": "54ecc8863c0550351eee5720f3be6a5d4a016025aa91cd6436cfec938d6a8d30" 25 | } 26 | }, 27 | "pubkey": "9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07", 28 | "path": "m/12381/60/3141592653/589793238", 29 | "uuid": "1d85ae20-35c5-4611-98e8-aa14a633906f", 30 | "version": 4 31 | } -------------------------------------------------------------------------------- /bls-keystore/src/test/resources/unsupportedKdfFunction.json: -------------------------------------------------------------------------------- 1 | { 2 | "crypto": { 3 | "kdf": { 4 | "function": "pbkdf3", 5 | "params": { 6 | "dklen": 32, 7 | "n": 262144, 8 | "p": 1, 9 | "r": 8, 10 | "salt": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" 11 | }, 12 | "message": "" 13 | }, 14 | "checksum": { 15 | "function": "sha256", 16 | "params": {}, 17 | "message": "149aafa27b041f3523c53d7acba1905fa6b1c90f9fef137568101f44b531a3cb" 18 | }, 19 | "cipher": { 20 | "function": "aes-128-ctr", 21 | "params": { 22 | "iv": "264daa3f303d7259501c93d997d84fe6" 23 | }, 24 | "message": "54ecc8863c0550351eee5720f3be6a5d4a016025aa91cd6436cfec938d6a8d30" 25 | } 26 | }, 27 | "pubkey": "9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07", 28 | "path": "m/12381/60/3141592653/589793238", 29 | "uuid": "1d85ae20-35c5-4611-98e8-aa14a633906f", 30 | "version": 4 31 | } -------------------------------------------------------------------------------- /bls-keystore/src/test/resources/unsupportedPBKDF2Prf.json: -------------------------------------------------------------------------------- 1 | { 2 | "crypto": { 3 | "kdf": { 4 | "function": "pbkdf2", 5 | "params": { 6 | "dklen": 32, 7 | "c": 262144, 8 | "prf": "hmac-sha512", 9 | "salt": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" 10 | }, 11 | "message": "" 12 | }, 13 | "checksum": { 14 | "function": "sha256", 15 | "params": {}, 16 | "message": "18b148af8e52920318084560fd766f9d09587b4915258dec0676cba5b0da09d8" 17 | }, 18 | "cipher": { 19 | "function": "aes-128-ctr", 20 | "params": { 21 | "iv": "264daa3f303d7259501c93d997d84fe6" 22 | }, 23 | "message": "a9249e0ca7315836356e4c7440361ff22b9fe71e2e2ed34fc1eb03976924ed48" 24 | } 25 | }, 26 | "pubkey": "9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07", 27 | "path": "m/12381/60/0/0", 28 | "uuid": "64625def-3331-4eea-ab6f-782f3ed16a83", 29 | "version": 4 30 | } -------------------------------------------------------------------------------- /bls-keystore/src/test/resources/v3TestVector.json: -------------------------------------------------------------------------------- 1 | { 2 | "crypto": { 3 | "kdf": { 4 | "function": "scrypt", 5 | "params": { 6 | "dklen": 32, 7 | "n": 262144, 8 | "p": 1, 9 | "r": 8, 10 | "salt": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" 11 | }, 12 | "message": "" 13 | }, 14 | "checksum": { 15 | "function": "sha256", 16 | "params": {}, 17 | "message": "149aafa27b041f3523c53d7acba1905fa6b1c90f9fef137568101f44b531a3cb" 18 | }, 19 | "cipher": { 20 | "function": "aes-128-ctr", 21 | "params": { 22 | "iv": "264daa3f303d7259501c93d997d84fe6" 23 | }, 24 | "message": "54ecc8863c0550351eee5720f3be6a5d4a016025aa91cd6436cfec938d6a8d30" 25 | } 26 | }, 27 | "pubkey": "9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07", 28 | "path": "m/12381/60/3141592653/589793238", 29 | "uuid": "1d85ae20-35c5-4611-98e8-aa14a633906f", 30 | "version": 3 31 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Set exports/opens flags required by Google Java Format and ErrorProne plugins. (JEP-396) 2 | org.gradle.jvmargs=-Xmx1g \ 3 | --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ 4 | --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ 5 | --add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \ 6 | --add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \ 7 | --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \ 8 | --add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \ 9 | --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ 10 | --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \ 11 | --add-exports java.base/sun.security.x509=ALL-UNNAMED \ 12 | --add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \ 13 | --add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \ 14 | --add-opens jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED 15 | hashicorpVaultVersion=1.9.2 16 | hashicorpVaultUrl=https://releases.hashicorp.com/vault 17 | -------------------------------------------------------------------------------- /gradle/formatter.properties: -------------------------------------------------------------------------------- 1 | #Whether to use 'space', 'tab' or 'mixed' (both) characters for indentation. 2 | #The default value is 'tab'. 3 | org.eclipse.jdt.core.formatter.tabulation.char=space 4 | 5 | #Number of spaces used for indentation in case 'space' characters 6 | #have been selected. The default value is 4. 7 | org.eclipse.jdt.core.formatter.tabulation.size=2 8 | 9 | #Number of spaces used for indentation in case 'mixed' characters 10 | #have been selected. The default value is 4. 11 | org.eclipse.jdt.core.formatter.indentation.size=1 12 | 13 | #Whether or not indentation characters are inserted into empty lines. 14 | #The default value is 'true'. 15 | org.eclipse.jdt.core.formatter.indent_empty_lines=false 16 | 17 | #Number of spaces used for multiline indentation. 18 | #The default value is 2. 19 | groovy.formatter.multiline.indentation=1 20 | 21 | #Length after which list are considered too long. These will be wrapped. 22 | #The default value is 30. 23 | groovy.formatter.longListLength=30 24 | 25 | #Whether opening braces position shall be the next line. 26 | #The default value is 'same'. 27 | groovy.formatter.braces.start=same 28 | 29 | #Whether closing braces position shall be the next line. 30 | #The default value is 'next'. 31 | groovy.formatter.braces.end=next 32 | 33 | #Remove unnecessary semicolons. The default value is 'false'. 34 | groovy.formatter.remove.unnecessary.semicolons=false 35 | 36 | org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line 37 | org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line 38 | org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line 39 | org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line 40 | org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line 41 | org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert 42 | org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line 43 | org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line 44 | org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line 45 | org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line 46 | org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert 47 | org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line 48 | org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line 49 | org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line 50 | 51 | org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert 52 | 53 | # Formatter can be buggy in CI 54 | ignoreFormatterProblems=true 55 | -------------------------------------------------------------------------------- /gradle/license-report-config/license-normalizer.json: -------------------------------------------------------------------------------- 1 | { 2 | "bundles" : [ 3 | { "bundleName" : "MIT", "licenseName" : "MIT License", "licenseUrl" : "https://opensource.org/licenses/MIT" }, 4 | { "bundleName" : "BSD", "licenseName" : "The BSD License", "licenseUrl" : "https://opensource.org/licenses/BSD-3-Clause" }, 5 | { "bundleName" : "CDDL-1.1", "licenseName" : "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1", "licenseUrl" : "https://spdx.org/licenses/CDDL-1.1.html" }, 6 | { "bundleName" : "Apache-2.0", "licenseName" : "Apache License, Version 2.0", "licenseUrl" : "https://www.apache.org/licenses/LICENSE-2.0" } 7 | ], 8 | "transformationRules" : [ 9 | { "bundleName" : "MIT", "licenseNamePattern" : "\"MIT\\sLicense\"" }, 10 | { "bundleName" : "BSD", "licenseNamePattern" : "BSD licence" }, 11 | { "bundleName" : "CDDL-1.1", "licenseNamePattern" : "(.*)Dual license consisting of the CDDL v1.1 and GPL v2(.*)" }, 12 | { "bundleName" : "Apache-2.0", "licenseNamePattern" : "(.*)Apache-2.0(.*)" } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /gradle/owasp-suppression.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | ^(?!pkg:maven/org\.json/json@).+$ 12 | cpe:/a:json-java_project:json-java 13 | 14 | 15 | 22 | CVE-2020-8908 23 | 24 | 25 | -------------------------------------------------------------------------------- /gradle/spotless.bash.license: -------------------------------------------------------------------------------- 1 | # Copyright $YEAR ConsenSys AG. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 4 | # the License. You may obtain a copy of the License at 5 | # 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 9 | # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | -------------------------------------------------------------------------------- /gradle/spotless.java.license: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright $YEAR ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Consensys/signers/6bfdaf111f6c8590ce77221f0b9b682fe5c5e28d/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /keystorage/aws/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | 14 | apply plugin: 'java-library' 15 | apply plugin: 'java-test-fixtures' 16 | 17 | jar { 18 | archiveBaseName = calculateJarName(project) 19 | manifest { 20 | attributes( 21 | 'Specification-Title': archiveBaseName.get(), 22 | 'Specification-Version': rootProject.version, 23 | 'Implementation-Title': archiveBaseName.get(), 24 | 'Implementation-Version': calculateVersion() 25 | ) 26 | } 27 | } 28 | 29 | testFixturesJar { 30 | archiveBaseName = calculateJarName(project) 31 | } 32 | 33 | dependencies { 34 | 35 | implementation 'software.amazon.awssdk:auth' 36 | implementation 'software.amazon.awssdk:secretsmanager' 37 | implementation 'com.google.guava:guava' 38 | implementation 'org.apache.logging.log4j:log4j-api' 39 | implementation project(':keystorage:common') 40 | runtimeOnly 'software.amazon.awssdk:sts' 41 | 42 | testImplementation 'org.assertj:assertj-core' 43 | testImplementation 'org.junit.jupiter:junit-jupiter-engine' 44 | testImplementation 'org.junit.jupiter:junit-jupiter-api' 45 | testImplementation 'org.junit.jupiter:junit-jupiter-params' 46 | 47 | errorprone("com.google.errorprone:error_prone_core") 48 | } 49 | -------------------------------------------------------------------------------- /keystorage/aws/src/main/java/tech/pegasys/signers/aws/AwsKeyIdentifier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.aws; 14 | 15 | import java.util.Objects; 16 | 17 | import software.amazon.awssdk.regions.Region; 18 | 19 | public class AwsKeyIdentifier { 20 | private final String accessKeyId; 21 | private final Region region; 22 | 23 | public AwsKeyIdentifier(final String accessKeyId, final Region region) { 24 | this.accessKeyId = accessKeyId; 25 | this.region = region; 26 | } 27 | 28 | public String getAccessKeyId() { 29 | return accessKeyId; 30 | } 31 | 32 | public Region getRegion() { 33 | return region; 34 | } 35 | 36 | @Override 37 | public boolean equals(Object o) { 38 | if (this == o) return true; 39 | if (o == null || getClass() != o.getClass()) return false; 40 | AwsKeyIdentifier that = (AwsKeyIdentifier) o; 41 | return accessKeyId.equals(that.accessKeyId) && region.equals(that.region); 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return Objects.hash(accessKeyId, region); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /keystorage/aws/src/test/java/tech/pegasys/signers/aws/AwsSecret.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.aws; 14 | 15 | import java.util.Objects; 16 | 17 | public class AwsSecret { 18 | private final String secretValue; 19 | private final String tagKey; 20 | private final String tagValue; 21 | 22 | public AwsSecret(final String secretValue, final String tagKey, final String tagValue) { 23 | this.secretValue = secretValue; 24 | this.tagKey = tagKey; 25 | this.tagValue = tagValue; 26 | } 27 | 28 | public String getSecretValue() { 29 | return secretValue; 30 | } 31 | 32 | public String getTagKey() { 33 | return tagKey; 34 | } 35 | 36 | public String getTagValue() { 37 | return tagValue; 38 | } 39 | 40 | @Override 41 | public boolean equals(final Object o) { 42 | if (this == o) return true; 43 | if (o == null || getClass() != o.getClass()) return false; 44 | AwsSecret that = (AwsSecret) o; 45 | return secretValue.equals(that.secretValue) 46 | && tagKey.equals(that.tagKey) 47 | && tagValue.equals(that.tagValue); 48 | } 49 | 50 | @Override 51 | public int hashCode() { 52 | return Objects.hash(secretValue, tagKey, tagValue); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /keystorage/azure/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | 14 | apply plugin: 'java-library' 15 | apply plugin: 'java-test-fixtures' 16 | 17 | jar { 18 | archiveBaseName = calculateJarName(project) 19 | manifest { 20 | attributes( 21 | 'Specification-Title': archiveBaseName.get(), 22 | 'Specification-Version': rootProject.version, 23 | 'Implementation-Title': archiveBaseName.get(), 24 | 'Implementation-Version': calculateVersion() 25 | ) 26 | } 27 | } 28 | 29 | testFixturesJar { 30 | archiveBaseName = calculateJarName(project) 31 | } 32 | 33 | dependencies { 34 | implementation 'org.apache.logging.log4j:log4j-api' 35 | implementation 'com.azure:azure-security-keyvault-secrets' 36 | implementation 'com.azure:azure-security-keyvault-keys' 37 | implementation 'com.azure:azure-identity' 38 | implementation project(':keystorage:common') 39 | 40 | runtimeOnly 'org.apache.logging.log4j:log4j-core' 41 | runtimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl' 42 | 43 | testImplementation 'org.assertj:assertj-core' 44 | testImplementation 'org.junit.jupiter:junit-jupiter-engine' 45 | testImplementation 'org.junit.jupiter:junit-jupiter-api' 46 | testImplementation 'org.junit.jupiter:junit-jupiter-params' 47 | testImplementation 'org.mockito:mockito-core' 48 | 49 | errorprone("com.google.errorprone:error_prone_core") 50 | } 51 | -------------------------------------------------------------------------------- /keystorage/build.gradle: -------------------------------------------------------------------------------- 1 | jar { enabled = false } 2 | -------------------------------------------------------------------------------- /keystorage/common/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | 14 | apply plugin: 'java-library' 15 | 16 | jar { 17 | archiveBaseName = calculateJarName(project) 18 | manifest { 19 | attributes( 20 | 'Specification-Title': archiveBaseName.get(), 21 | 'Specification-Version': rootProject.version, 22 | 'Implementation-Title': archiveBaseName.get(), 23 | 'Implementation-Version': calculateVersion() 24 | ) 25 | } 26 | } 27 | 28 | dependencies { 29 | implementation 'org.apache.logging.log4j:log4j-api' 30 | implementation 'com.google.guava:guava' 31 | runtimeOnly 'org.apache.logging.log4j:log4j-core' 32 | runtimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl' 33 | 34 | testImplementation 'org.assertj:assertj-core' 35 | testImplementation 'de.neuland-bfi:assertj-logging-log4j' 36 | testImplementation 'org.junit.jupiter:junit-jupiter-engine' 37 | testImplementation 'org.junit.jupiter:junit-jupiter-api' 38 | testImplementation 'org.junit.jupiter:junit-jupiter-params' 39 | 40 | testRuntimeOnly 'org.apache.logging.log4j:log4j-core' 41 | testRuntimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl' 42 | } 43 | -------------------------------------------------------------------------------- /keystorage/common/src/main/java/tech/pegasys/signers/common/MappedResults.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.common; 14 | 15 | import java.util.Collection; 16 | import java.util.Collections; 17 | import java.util.HashSet; 18 | import java.util.List; 19 | import java.util.stream.Collectors; 20 | import java.util.stream.Stream; 21 | 22 | /** Contains Collection of Secret value result and count of errors. */ 23 | public class MappedResults { 24 | private final Collection values; 25 | private int errorCount; 26 | 27 | MappedResults(final Collection values, final int errorCount) { 28 | this.values = values; 29 | this.errorCount = errorCount; 30 | } 31 | 32 | public static MappedResults errorResult() { 33 | return new MappedResults<>(Collections.emptyList(), 1); 34 | } 35 | 36 | public static MappedResults newSetInstance() { 37 | return new MappedResults<>(new HashSet<>(), 0); 38 | } 39 | 40 | public static MappedResults newInstance(final Collection values, final int errorCount) { 41 | return new MappedResults<>(values, errorCount); 42 | } 43 | 44 | public static MappedResults merge( 45 | final MappedResults first, final MappedResults second) { 46 | final List combinedList = 47 | Stream.concat(first.values.stream(), second.values.stream()).collect(Collectors.toList()); 48 | final int errorCount = first.errorCount + second.errorCount; 49 | return new MappedResults<>(combinedList, errorCount); 50 | } 51 | 52 | public void mergeErrorCount(final int otherErrorCount) { 53 | this.errorCount += otherErrorCount; 54 | } 55 | 56 | public Collection getValues() { 57 | return values; 58 | } 59 | 60 | public int getErrorCount() { 61 | return errorCount; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /keystorage/common/src/main/java/tech/pegasys/signers/common/SecretValueMapperUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.common; 14 | 15 | import java.util.Objects; 16 | import java.util.Set; 17 | import java.util.concurrent.atomic.AtomicInteger; 18 | import java.util.function.BiFunction; 19 | import java.util.stream.Collectors; 20 | 21 | import com.google.common.collect.Streams; 22 | import org.apache.logging.log4j.LogManager; 23 | import org.apache.logging.log4j.Logger; 24 | 25 | public class SecretValueMapperUtil { 26 | private static final Logger LOG = LogManager.getLogger(); 27 | 28 | public static MappedResults mapSecretValue( 29 | BiFunction mapper, String secretName, String secretValue) { 30 | final AtomicInteger errorCount = new AtomicInteger(0); 31 | final Set result = 32 | Streams.mapWithIndex( 33 | secretValue.lines(), 34 | (value, index) -> { 35 | final R obj = mapper.apply(secretName, value); 36 | if (obj == null) { 37 | LOG.warn( 38 | "Value from secret name {} at index {} was not mapped and discarded.", 39 | secretName, 40 | index); 41 | errorCount.incrementAndGet(); 42 | } 43 | return obj; 44 | }) 45 | .filter(Objects::nonNull) 46 | .collect(Collectors.toSet()); 47 | return MappedResults.newInstance(result, errorCount.intValue()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /keystorage/hashicorp/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | 14 | apply plugin: 'java-library' 15 | apply plugin: 'java-test-fixtures' 16 | 17 | jar { 18 | archiveBaseName = calculateJarName(project) 19 | manifest { 20 | attributes( 21 | 'Specification-Title': archiveBaseName.get(), 22 | 'Specification-Version': rootProject.version, 23 | 'Implementation-Title': archiveBaseName.get(), 24 | 'Implementation-Version': calculateVersion() 25 | ) 26 | } 27 | } 28 | 29 | testFixturesJar { 30 | archiveBaseName = calculateJarName(project) 31 | } 32 | 33 | dependencies { 34 | implementation 'io.vertx:vertx-core' 35 | implementation 'org.apache.logging.log4j:log4j-api' 36 | 37 | implementation 'org.apache.tuweni:tuweni-toml' 38 | implementation 'org.apache.tuweni:tuweni-net' 39 | implementation 'org.bouncycastle:bcpkix-jdk15on' 40 | implementation 'org.bouncycastle:bcprov-jdk15on' 41 | 42 | runtimeOnly 'org.apache.logging.log4j:log4j-core' 43 | runtimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl' 44 | 45 | testImplementation 'org.assertj:assertj-core' 46 | testImplementation 'org.junit.jupiter:junit-jupiter-engine' 47 | testImplementation 'org.junit.jupiter:junit-jupiter-api' 48 | testImplementation 'org.junit.jupiter:junit-jupiter-params' 49 | testImplementation 'org.mockito:mockito-core' 50 | 51 | integrationTestImplementation 'org.assertj:assertj-core' 52 | integrationTestImplementation 'org.junit.jupiter:junit-jupiter-api' 53 | integrationTestImplementation 'org.junit.jupiter:junit-jupiter-engine' 54 | integrationTestImplementation 'org.mock-server:mockserver-netty' 55 | integrationTestImplementation sourceSets.testFixtures.output 56 | 57 | errorprone("com.google.errorprone:error_prone_core") 58 | 59 | testFixturesImplementation 'org.apache.logging.log4j:log4j-api' 60 | testFixturesImplementation 'org.bouncycastle:bcpkix-jdk15on' 61 | testFixturesImplementation 'org.bouncycastle:bcprov-jdk15on' 62 | testFixturesImplementation 'com.fasterxml.jackson.core:jackson-databind' 63 | testFixturesImplementation 'org.assertj:assertj-core' 64 | testFixturesImplementation 'org.awaitility:awaitility' 65 | testFixturesImplementation 'org.apache.tuweni:tuweni-net' 66 | testFixturesImplementation 'org.zeroturnaround:zt-exec' 67 | } 68 | -------------------------------------------------------------------------------- /keystorage/hashicorp/src/main/java/tech/pegasys/signers/hashicorp/HashicorpException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.hashicorp; 14 | 15 | public class HashicorpException extends RuntimeException { 16 | 17 | public HashicorpException() {} 18 | 19 | public HashicorpException(final String message) { 20 | super(message); 21 | } 22 | 23 | public HashicorpException(final String message, final Throwable cause) { 24 | super(message, cause); 25 | } 26 | 27 | public HashicorpException(final Throwable cause) { 28 | super(cause); 29 | } 30 | 31 | public HashicorpException( 32 | final String message, 33 | final Throwable cause, 34 | final boolean enableSuppression, 35 | final boolean writableStackTrace) { 36 | super(message, cause, enableSuppression, writableStackTrace); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /keystorage/hashicorp/src/main/java/tech/pegasys/signers/hashicorp/HashicorpKVResponseMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.hashicorp; 14 | 15 | import java.util.Collections; 16 | import java.util.Map; 17 | import java.util.Objects; 18 | import java.util.Optional; 19 | import java.util.stream.Collectors; 20 | 21 | import io.vertx.core.json.DecodeException; 22 | import io.vertx.core.json.JsonObject; 23 | 24 | public class HashicorpKVResponseMapper { 25 | public static final String ERROR_INVALID_JSON = "Invalid response returned from Hashicorp Vault"; 26 | 27 | /** 28 | * Convert Hashicorp KV Version 2 Secret Engine JSON response to map of key/values 29 | * 30 | * @param json response from Hashicorp Vault 31 | * @return All key/value pairs 32 | */ 33 | public static Map from(final String json) { 34 | if (json == null) { 35 | throw new HashicorpException(ERROR_INVALID_JSON); 36 | } 37 | final JsonObject jsonResponse; 38 | try { 39 | jsonResponse = new JsonObject(json); 40 | } catch (final DecodeException de) { 41 | throw new HashicorpException(ERROR_INVALID_JSON, de); 42 | } 43 | 44 | // expecting Hashicorp kv-v2 secret engine compatible JSON json 45 | final JsonObject keyData = 46 | Optional.ofNullable(jsonResponse.getJsonObject("data")) 47 | .map(jo -> jo.getJsonObject("data")) 48 | .orElseThrow(() -> new HashicorpException(ERROR_INVALID_JSON)); 49 | return Collections.unmodifiableMap( 50 | keyData.stream() 51 | .filter(entry -> Objects.nonNull(entry.getValue())) 52 | .collect( 53 | Collectors.toMap(Map.Entry::getKey, HashicorpKVResponseMapper::getValueToString))); 54 | } 55 | 56 | private static String getValueToString(final Map.Entry v) { 57 | return v.getValue().toString(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /keystorage/hashicorp/src/main/java/tech/pegasys/signers/hashicorp/TrustStoreType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.hashicorp; 14 | 15 | import java.util.EnumSet; 16 | import java.util.Optional; 17 | 18 | public enum TrustStoreType { 19 | JKS(true), 20 | PKCS12(true), 21 | WHITELIST(false), 22 | ALLOWLIST(false), 23 | PEM(false); 24 | 25 | private boolean passwordRequired; 26 | 27 | TrustStoreType(final boolean passwordRequired) { 28 | this.passwordRequired = passwordRequired; 29 | } 30 | 31 | public boolean isPasswordRequired() { 32 | return passwordRequired; 33 | } 34 | 35 | public static Optional fromString(final String tsType) { 36 | return EnumSet.allOf(TrustStoreType.class).stream() 37 | .filter(t -> t.name().equals(tsType)) 38 | .findAny(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /keystorage/hashicorp/src/main/java/tech/pegasys/signers/hashicorp/config/ConnectionParameters.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.hashicorp.config; 14 | 15 | import java.net.URI; 16 | import java.util.Optional; 17 | 18 | public class ConnectionParameters { 19 | private static final Long DEFAULT_TIMEOUT_MILLISECONDS = 10_000L; 20 | private static final Integer DEFAULT_SERVER_PORT = 8200; 21 | private final String serverHost; 22 | private final int serverPort; 23 | private final Optional tlsOptions; 24 | private final long timeoutMs; 25 | 26 | private final URI vaultURI; 27 | 28 | /* Optional parameters will be set to their defaults when connecting */ 29 | public ConnectionParameters( 30 | final String serverHost, 31 | final Optional serverPort, 32 | final Optional tlsOptions, 33 | final Optional timeoutMs) { 34 | this.serverHost = serverHost; 35 | this.serverPort = serverPort.orElse(DEFAULT_SERVER_PORT); 36 | this.tlsOptions = tlsOptions; 37 | this.timeoutMs = timeoutMs.orElse(DEFAULT_TIMEOUT_MILLISECONDS); 38 | final String scheme = tlsOptions.isPresent() ? "https" : "http"; 39 | this.vaultURI = URI.create(String.format("%s://%s:%d", scheme, serverHost, this.serverPort)); 40 | } 41 | 42 | public String getServerHost() { 43 | return serverHost; 44 | } 45 | 46 | public int getServerPort() { 47 | return serverPort; 48 | } 49 | 50 | public Optional getTlsOptions() { 51 | return tlsOptions; 52 | } 53 | 54 | public long getTimeoutMilliseconds() { 55 | return timeoutMs; 56 | } 57 | 58 | public URI getVaultURI() { 59 | return vaultURI; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /keystorage/hashicorp/src/main/java/tech/pegasys/signers/hashicorp/config/HashicorpKeyConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.hashicorp.config; 14 | 15 | public class HashicorpKeyConfig { 16 | 17 | private final ConnectionParameters connectionParams; 18 | private final KeyDefinition keyDefinition; 19 | 20 | public HashicorpKeyConfig( 21 | final ConnectionParameters connectionParams, final KeyDefinition keyDefinition) { 22 | this.connectionParams = connectionParams; 23 | this.keyDefinition = keyDefinition; 24 | } 25 | 26 | public ConnectionParameters getConnectionParams() { 27 | return connectionParams; 28 | } 29 | 30 | public KeyDefinition getKeyDefinition() { 31 | return keyDefinition; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /keystorage/hashicorp/src/main/java/tech/pegasys/signers/hashicorp/config/KeyDefinition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.hashicorp.config; 14 | 15 | import java.util.Optional; 16 | 17 | public class KeyDefinition { 18 | 19 | private String keyPath; 20 | private Optional keyName; 21 | private String token; 22 | 23 | public KeyDefinition(final String keyPath, final Optional keyName, final String token) { 24 | this.keyPath = keyPath; 25 | this.keyName = keyName; 26 | this.token = token; 27 | } 28 | 29 | public String getKeyPath() { 30 | return keyPath; 31 | } 32 | 33 | public Optional getKeyName() { 34 | return keyName; 35 | } 36 | 37 | public String getToken() { 38 | return token; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /keystorage/hashicorp/src/main/java/tech/pegasys/signers/hashicorp/config/TlsOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.hashicorp.config; 14 | 15 | import tech.pegasys.signers.hashicorp.TrustStoreType; 16 | 17 | import java.nio.file.Path; 18 | import java.util.Optional; 19 | 20 | public class TlsOptions { 21 | 22 | private final Optional trustStoreType; 23 | private final Path trustStorePath; 24 | private final String trustStorePassword; 25 | 26 | public TlsOptions( 27 | final Optional trustStoreType, 28 | final Path trustStorePath, 29 | final String trustStorePassword) { 30 | this.trustStoreType = trustStoreType; 31 | this.trustStorePath = trustStorePath; 32 | this.trustStorePassword = trustStorePassword; 33 | } 34 | 35 | public Optional getTrustStoreType() { 36 | return trustStoreType; 37 | } 38 | 39 | public Path getTrustStorePath() { 40 | return trustStorePath; 41 | } 42 | 43 | public String getTrustStorePassword() { 44 | return trustStorePassword; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /keystorage/hashicorp/src/main/java/tech/pegasys/signers/hashicorp/config/loader/toml/TomlParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.hashicorp.config.loader.toml; 14 | 15 | import tech.pegasys.signers.hashicorp.HashicorpException; 16 | 17 | import java.io.IOException; 18 | import java.nio.charset.StandardCharsets; 19 | import java.nio.file.Files; 20 | import java.nio.file.Path; 21 | import java.util.stream.Collectors; 22 | 23 | import org.apache.logging.log4j.LogManager; 24 | import org.apache.logging.log4j.Logger; 25 | import org.apache.tuweni.toml.Toml; 26 | import org.apache.tuweni.toml.TomlParseError; 27 | import org.apache.tuweni.toml.TomlParseResult; 28 | 29 | public class TomlParser { 30 | private static final Logger LOG = LogManager.getLogger(); 31 | 32 | public TomlParseResult getTomlParseResult(final Path tomlConfigurationFile) { 33 | try { 34 | return getTomlParseResult(Files.readString(tomlConfigurationFile, StandardCharsets.UTF_8)); 35 | } catch (final IOException e) { 36 | throw new HashicorpException("Error reading Hashicorp configuration file", e); 37 | } 38 | } 39 | 40 | public TomlParseResult getTomlParseResult(final String tomlConfiguration) { 41 | final TomlParseResult tomlParseResult = Toml.parse(tomlConfiguration); 42 | if (tomlParseResult.hasErrors()) { 43 | LOG.debug(() -> joinErrors(tomlParseResult)); 44 | throw new HashicorpException("Error parsing Hashicorp configuration"); 45 | } 46 | return tomlParseResult; 47 | } 48 | 49 | private String joinErrors(final TomlParseResult result) { 50 | return result.errors().stream() 51 | .map(TomlParseError::toString) 52 | .collect(Collectors.joining(System.lineSeparator())); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /keystorage/hashicorp/src/test/java/tech/pegasys/signers/hashicorp/HashicorpConnectionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.hashicorp; 14 | 15 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 16 | 17 | import tech.pegasys.signers.hashicorp.config.ConnectionParameters; 18 | import tech.pegasys.signers.hashicorp.config.TlsOptions; 19 | 20 | import java.io.EOFException; 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.net.URL; 24 | import java.nio.file.Path; 25 | import java.util.Optional; 26 | 27 | import com.google.common.io.Resources; 28 | import org.junit.jupiter.api.Test; 29 | 30 | public class HashicorpConnectionTest { 31 | 32 | private static final String CONFIGURED_HOST = "Host"; 33 | private final HashicorpConnectionFactory connectionFactory = new HashicorpConnectionFactory(); 34 | 35 | @Test 36 | void missingJksTrustStoreFileThrowsHashicorpException() throws IOException { 37 | 38 | final File tempFile = File.createTempFile("trustStore", ".tmp"); 39 | tempFile.deleteOnExit(); 40 | final TlsOptions tlsOptions = 41 | new TlsOptions(Optional.of(TrustStoreType.JKS), tempFile.toPath(), "anyPassword"); 42 | 43 | final ConnectionParameters params = 44 | new ConnectionParameters( 45 | CONFIGURED_HOST, Optional.empty(), Optional.of(tlsOptions), Optional.of(10L)); 46 | 47 | assertThatThrownBy(() -> connectionFactory.create(params)) 48 | .isInstanceOf(HashicorpException.class) 49 | .hasMessage("Unable to initialise connection to hashicorp vault.") 50 | .getCause() 51 | .isInstanceOf(EOFException.class); 52 | } 53 | 54 | @Test 55 | void pkcs12FileWithIncorrectPasswordThrowsHashicorpException() { 56 | 57 | final URL sslCertificate = Resources.getResource("tls/cert1.pfx"); 58 | final Path keystorePath = Path.of(sslCertificate.getPath()); 59 | 60 | // valid password is "password" 61 | final TlsOptions tlsOptions = 62 | new TlsOptions(Optional.of(TrustStoreType.PKCS12), keystorePath, "wrongPassword"); 63 | 64 | final ConnectionParameters params = 65 | new ConnectionParameters( 66 | CONFIGURED_HOST, Optional.empty(), Optional.of(tlsOptions), Optional.of(10L)); 67 | 68 | assertThatThrownBy(() -> connectionFactory.create(params)) 69 | .isInstanceOf(HashicorpException.class) 70 | .hasMessage("Unable to initialise connection to hashicorp vault.") 71 | .getCause() 72 | .isInstanceOf(IOException.class) 73 | .hasMessage("keystore password was incorrect"); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /keystorage/hashicorp/src/test/java/tech/pegasys/signers/hashicorp/HashicorpKVResponseMapperTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.hashicorp; 14 | 15 | import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; 16 | 17 | import java.util.Map; 18 | 19 | import org.assertj.core.api.Assertions; 20 | import org.junit.jupiter.api.Test; 21 | 22 | class HashicorpKVResponseMapperTest { 23 | 24 | private static final String VALID_JSON_RESPONSE = 25 | "{\n" 26 | + " \"request_id\": \"39ae72e7-ef58-ab8b-9aef-4473a4ea2c46\",\n" 27 | + " \"lease_id\": \"\",\n" 28 | + " \"renewable\": false,\n" 29 | + " \"lease_duration\": 0,\n" 30 | + " \"data\": {\n" 31 | + " \"data\": {\n" 32 | + " \"dbKey1\": \"1c2c450cedaa416329fef5900854d55c00046224dffd0075b5057a088b48f9bf\",\n" 33 | + " \"value\": \"ccccaaacedaa416329fef5900854d55c00046224dffd0075b5057a088b48f9bf\"\n" 34 | + " },\n" 35 | + " \"metadata\": {\n" 36 | + " \"created_time\": \"2019-11-06T08:21:41.656367376Z\",\n" 37 | + " \"deletion_time\": \"\",\n" 38 | + " \"destroyed\": false,\n" 39 | + " \"version\": 1\n" 40 | + " }\n" 41 | + " },\n" 42 | + " \"wrap_info\": null,\n" 43 | + " \"warnings\": null,\n" 44 | + " \"auth\": null\n" 45 | + "}"; 46 | 47 | @Test 48 | void exceptionThrownWhenParsingNullJsonInput() { 49 | assertThatThrownBy(() -> HashicorpKVResponseMapper.from(null)) 50 | .isInstanceOf(HashicorpException.class) 51 | .hasMessage(HashicorpKVResponseMapper.ERROR_INVALID_JSON); 52 | } 53 | 54 | @Test 55 | void exceptionThrownWhenParsingInvalidJsonInput() { 56 | assertThatThrownBy(() -> HashicorpKVResponseMapper.from("invalidjson{")) 57 | .isInstanceOf(HashicorpException.class) 58 | .hasMessage(HashicorpKVResponseMapper.ERROR_INVALID_JSON); 59 | } 60 | 61 | @Test 62 | void exceptionThrownWhenParsingUnexpectedJsonInput() { 63 | assertThatThrownBy(() -> HashicorpKVResponseMapper.from("{\"test\":\"value\"}")) 64 | .isInstanceOf(HashicorpException.class) 65 | .hasMessage(HashicorpKVResponseMapper.ERROR_INVALID_JSON); 66 | } 67 | 68 | @Test 69 | void mapReturnedFromValidJsonResponse() { 70 | final Map kvMap = HashicorpKVResponseMapper.from(VALID_JSON_RESPONSE); 71 | Assertions.assertThat(kvMap).containsOnlyKeys("value", "dbKey1").isNotNull(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /keystorage/hashicorp/src/test/java/tech/pegasys/signers/hashicorp/TrustStoreTypeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.hashicorp; 14 | 15 | import static org.junit.jupiter.api.Assertions.assertEquals; 16 | 17 | import java.util.Optional; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | class TrustStoreTypeTest { 22 | 23 | @Test 24 | void trustStoreTypeCreatedFromValidValue() { 25 | assertEquals(Optional.of(TrustStoreType.PEM), TrustStoreType.fromString("PEM")); 26 | } 27 | 28 | @Test 29 | void turstStoreTypeEmptyFromInvalidValue() { 30 | assertEquals(Optional.empty(), TrustStoreType.fromString("X")); 31 | assertEquals(Optional.empty(), TrustStoreType.fromString("pem")); 32 | assertEquals(Optional.empty(), TrustStoreType.fromString(null)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /keystorage/hashicorp/src/test/resources/tls/cert1.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Consensys/signers/6bfdaf111f6c8590ce77221f0b9b682fe5c5e28d/keystorage/hashicorp/src/test/resources/tls/cert1.pfx -------------------------------------------------------------------------------- /keystorage/hashicorp/src/testFixtures/java/tech/pegasys/signers/hashicorp/dsl/HashicorpVaultCommands.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.hashicorp.dsl; 14 | 15 | public class HashicorpVaultCommands { 16 | 17 | private final String vaultCommand; 18 | private final String vaultUrl; 19 | 20 | public HashicorpVaultCommands(final String vaultCommand, final String vaultUrl) { 21 | this.vaultCommand = vaultCommand; 22 | this.vaultUrl = vaultUrl; 23 | } 24 | 25 | public String[] initCommand() { 26 | return new String[] { 27 | vaultCommand, 28 | "operator", 29 | "init", 30 | "-key-shares=1", 31 | "-key-threshold=1", 32 | "-format=json", 33 | "-address=" + vaultUrl 34 | }; 35 | } 36 | 37 | public String[] enableSecretEngineCommand(final String vaultRootPath) { 38 | return new String[] { 39 | vaultCommand, "secrets", "enable", "-address=" + vaultUrl, "-path=" + vaultRootPath, "kv-v2", 40 | }; 41 | } 42 | 43 | public String[] unseal(final String unsealKey) { 44 | return new String[] { 45 | vaultCommand, "operator", "unseal", "-address=" + vaultUrl, "-format=json", unsealKey 46 | }; 47 | } 48 | 49 | public String[] putSecretCommand(final String key, final String value, final String path) { 50 | final String paramString = String.format("%s=%s", key, value); 51 | return new String[] { 52 | vaultCommand, "kv", "put", "-address=" + vaultUrl, path, paramString, 53 | }; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /keystorage/hashicorp/src/testFixtures/java/tech/pegasys/signers/hashicorp/dsl/HashicorpVaultTokens.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.hashicorp.dsl; 14 | 15 | public class HashicorpVaultTokens { 16 | private final String unsealKey; 17 | private final String rootToken; 18 | 19 | public HashicorpVaultTokens(final String unsealKey, final String rootToken) { 20 | this.unsealKey = unsealKey; 21 | this.rootToken = rootToken; 22 | } 23 | 24 | public String getUnsealKey() { 25 | return unsealKey; 26 | } 27 | 28 | public String getRootToken() { 29 | return rootToken; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /keystorage/interlock/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | 14 | apply plugin: 'java-library' 15 | 16 | jar { 17 | archiveBaseName = calculateJarName(project) 18 | manifest { 19 | attributes( 20 | 'Specification-Title': archiveBaseName.get(), 21 | 'Specification-Version': rootProject.version, 22 | 'Implementation-Title': archiveBaseName.get(), 23 | 'Implementation-Version': calculateVersion() 24 | ) 25 | } 26 | } 27 | 28 | dependencies { 29 | implementation 'io.vertx:vertx-core' 30 | implementation 'org.apache.logging.log4j:log4j-api' 31 | 32 | implementation 'org.apache.tuweni:tuweni-toml' 33 | implementation 'org.apache.tuweni:tuweni-net' 34 | implementation 'org.apache.commons:commons-lang3' 35 | implementation 'commons-io:commons-io' 36 | 37 | runtimeOnly 'org.apache.logging.log4j:log4j-core' 38 | runtimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl' 39 | runtimeOnly 'org.bouncycastle:bcpkix-jdk15on' 40 | runtimeOnly 'org.bouncycastle:bcprov-jdk15on' 41 | 42 | testImplementation 'org.assertj:assertj-core' 43 | testImplementation 'org.junit.jupiter:junit-jupiter-engine' 44 | testImplementation 'org.junit.jupiter:junit-jupiter-api' 45 | testImplementation 'org.junit.jupiter:junit-jupiter-params' 46 | testImplementation 'org.mockito:mockito-core' 47 | 48 | testRuntimeOnly 'org.bouncycastle:bcpkix-jdk15on' 49 | testRuntimeOnly 'org.bouncycastle:bcprov-jdk15on' 50 | testRuntimeOnly 'org.apache.logging.log4j:log4j-core' 51 | testRuntimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl' 52 | testRuntimeOnly 'org.apache.logging.log4j:log4j-api' 53 | } 54 | -------------------------------------------------------------------------------- /keystorage/interlock/src/main/java/tech/pegasys/signers/interlock/InterlockClientException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.interlock; 14 | 15 | public class InterlockClientException extends RuntimeException { 16 | public InterlockClientException(final String message) { 17 | super(message); 18 | } 19 | 20 | public InterlockClientException(final String message, final Throwable cause) { 21 | super(message, cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /keystorage/interlock/src/main/java/tech/pegasys/signers/interlock/InterlockSession.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.interlock; 14 | 15 | import org.apache.tuweni.bytes.Bytes; 16 | 17 | public interface InterlockSession extends AutoCloseable { 18 | 19 | /** 20 | * Fetch key from given path. It is expected that the private key is stored in hex format in given 21 | * file. 22 | * 23 | * @param keyPath The path of key file in Interlock, for instance "/bls/key1.txt" 24 | * @return org.apache.tuweni.bytes.Bytes representing raw private key. 25 | * @throws InterlockClientException In case of an error while fetching key 26 | */ 27 | Bytes fetchKey(String keyPath) throws InterlockClientException; 28 | 29 | /** Logout from Interlock Session */ 30 | @Override 31 | void close(); 32 | } 33 | -------------------------------------------------------------------------------- /keystorage/interlock/src/main/java/tech/pegasys/signers/interlock/InterlockSessionFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.interlock; 14 | 15 | import java.net.URI; 16 | 17 | public interface InterlockSessionFactory { 18 | InterlockSession newSession(URI interlockURI, String volume, String password); 19 | } 20 | -------------------------------------------------------------------------------- /keystorage/interlock/src/main/java/tech/pegasys/signers/interlock/InterlockSessionFactoryProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.interlock; 14 | 15 | import tech.pegasys.signers.interlock.vertx.InterlockSessionFactoryImpl; 16 | 17 | import java.nio.file.Path; 18 | import java.time.Duration; 19 | 20 | import io.vertx.core.Vertx; 21 | import org.apache.commons.lang3.StringUtils; 22 | 23 | public class InterlockSessionFactoryProvider { 24 | private static final String HTTP_CLIENT_TIMEOUT_ENV = "INTERLOCK_CLIENT_TIMEOUT_MS"; 25 | private static final int DEFAULT_TIMEOUT_MS = 5000; 26 | private static final Duration HTTP_CLIENT_TIMEOUT_DURATION = timeoutDuration(); 27 | 28 | public static InterlockSessionFactoryImpl newInstance( 29 | final Vertx vertx, final Path knownServersFile) { 30 | return new InterlockSessionFactoryImpl(vertx, knownServersFile, HTTP_CLIENT_TIMEOUT_DURATION); 31 | } 32 | 33 | private static Duration timeoutDuration() { 34 | final String timeoutStr = System.getenv(HTTP_CLIENT_TIMEOUT_ENV); 35 | if (StringUtils.isBlank(timeoutStr)) { 36 | return Duration.ofMillis(DEFAULT_TIMEOUT_MS); 37 | } 38 | 39 | try { 40 | final int timeout = Integer.parseInt(timeoutStr); 41 | if (timeout < 0) { 42 | throw new NumberFormatException(); 43 | } 44 | return Duration.ofMillis(timeout); 45 | } catch (final NumberFormatException e) { 46 | throw new IllegalArgumentException("Invalid Interlock client timeout " + timeoutStr); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /keystorage/interlock/src/main/java/tech/pegasys/signers/interlock/model/ApiAuth.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.interlock.model; 14 | 15 | import java.util.List; 16 | 17 | public class ApiAuth { 18 | public static final String XSRF_TOKEN_HEADER = "X-XSRFToken"; 19 | private final String token; 20 | private final List cookies; 21 | 22 | public ApiAuth(final String token, final List cookies) { 23 | this.token = token; 24 | this.cookies = cookies; 25 | } 26 | 27 | public List getCookies() { 28 | return cookies; 29 | } 30 | 31 | public String getToken() { 32 | return token; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /keystorage/interlock/src/main/java/tech/pegasys/signers/interlock/vertx/InterlockSessionImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.interlock.vertx; 14 | 15 | import tech.pegasys.signers.interlock.InterlockClientException; 16 | import tech.pegasys.signers.interlock.InterlockSession; 17 | import tech.pegasys.signers.interlock.model.ApiAuth; 18 | import tech.pegasys.signers.interlock.vertx.operations.FileDownloadIdOperation; 19 | import tech.pegasys.signers.interlock.vertx.operations.FileDownloadOperation; 20 | import tech.pegasys.signers.interlock.vertx.operations.LogoutOperation; 21 | 22 | import io.vertx.core.http.HttpClient; 23 | import org.apache.logging.log4j.LogManager; 24 | import org.apache.logging.log4j.Logger; 25 | import org.apache.tuweni.bytes.Bytes; 26 | 27 | public class InterlockSessionImpl implements InterlockSession { 28 | private static final Logger LOG = LogManager.getLogger(); 29 | 30 | private final ApiAuth apiAuth; 31 | private final HttpClient httpClient; 32 | 33 | public InterlockSessionImpl(final HttpClient httpClient, final ApiAuth apiAuth) { 34 | this.httpClient = httpClient; 35 | this.apiAuth = apiAuth; 36 | } 37 | 38 | @Override 39 | public Bytes fetchKey(final String keyPath) throws InterlockClientException { 40 | LOG.trace("Fetching key from {}.", keyPath); 41 | try { 42 | final String downloadId = 43 | new FileDownloadIdOperation(httpClient, apiAuth, keyPath).waitForResponse(); 44 | final String keyStr = 45 | new FileDownloadOperation(httpClient, apiAuth, downloadId).waitForResponse(); 46 | return Bytes.fromHexString(keyStr); 47 | } catch (final InterlockClientException e) { 48 | LOG.warn("Downloading {} failed due to: {}", keyPath, e.getMessage()); 49 | throw new InterlockClientException("Unable to download " + keyPath); 50 | } catch (final IllegalArgumentException e) { 51 | LOG.warn( 52 | "Downloaded content from {} failed to convert to Bytes: {}", keyPath, e.getMessage()); 53 | throw new InterlockClientException("Invalid content received from " + keyPath); 54 | } 55 | } 56 | 57 | @Override 58 | public void close() { 59 | LOG.trace("Closing session"); 60 | try { 61 | new LogoutOperation(httpClient, apiAuth).waitForResponse(); 62 | } catch (final RuntimeException e) { 63 | LOG.warn("Interlock Session Logout operation failed: " + e.getMessage()); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /keystorage/interlock/src/main/java/tech/pegasys/signers/interlock/vertx/operations/ApiOperation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.interlock.vertx.operations; 14 | 15 | import tech.pegasys.signers.interlock.InterlockClientException; 16 | 17 | public interface ApiOperation { 18 | T waitForResponse() throws InterlockClientException; 19 | } 20 | -------------------------------------------------------------------------------- /keystorage/interlock/src/main/java/tech/pegasys/signers/interlock/vertx/operations/FileDownloadIdOperation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.interlock.vertx.operations; 14 | 15 | import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; 16 | import static io.vertx.core.http.HttpHeaders.COOKIE; 17 | import static io.vertx.core.http.HttpMethod.POST; 18 | import static tech.pegasys.signers.interlock.model.ApiAuth.XSRF_TOKEN_HEADER; 19 | 20 | import tech.pegasys.signers.interlock.model.ApiAuth; 21 | 22 | import io.vertx.core.MultiMap; 23 | import io.vertx.core.http.HttpClient; 24 | import io.vertx.core.json.JsonObject; 25 | 26 | public class FileDownloadIdOperation extends AbstractOperation { 27 | private final HttpClient httpClient; 28 | private final ApiAuth apiAuth; 29 | private final String keyPath; 30 | 31 | public FileDownloadIdOperation( 32 | final HttpClient httpClient, final ApiAuth apiAuth, final String keyPath) { 33 | this.httpClient = httpClient; 34 | this.apiAuth = apiAuth; 35 | this.keyPath = keyPath; 36 | } 37 | 38 | @Override 39 | protected void invoke() { 40 | final String body = new JsonObject().put("path", keyPath).encode(); 41 | httpClient 42 | .request(POST, "/api/file/download") 43 | .onSuccess( 44 | request -> { 45 | request.response().onSuccess(this::handle).onFailure(this::handleException); 46 | request.exceptionHandler(this::handleException); 47 | request.putHeader(CONTENT_TYPE, "application/json"); 48 | request.putHeader(XSRF_TOKEN_HEADER, apiAuth.getToken()); 49 | request.putHeader(COOKIE.toString(), apiAuth.getCookies()); 50 | request.end(body); 51 | }) 52 | .onFailure(this::handleException); 53 | } 54 | 55 | @Override 56 | protected String processJsonResponse(final JsonObject json, final MultiMap headers) { 57 | return json.getString("response"); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /keystorage/interlock/src/main/java/tech/pegasys/signers/interlock/vertx/operations/FileDownloadOperation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.interlock.vertx.operations; 14 | 15 | import static io.vertx.core.http.HttpHeaders.COOKIE; 16 | import static io.vertx.core.http.HttpMethod.GET; 17 | 18 | import tech.pegasys.signers.interlock.model.ApiAuth; 19 | 20 | import java.net.URLEncoder; 21 | import java.nio.charset.StandardCharsets; 22 | 23 | import io.vertx.core.buffer.Buffer; 24 | import io.vertx.core.http.HttpClient; 25 | import io.vertx.core.http.HttpClientResponse; 26 | 27 | public class FileDownloadOperation extends AbstractOperation { 28 | private final HttpClient httpClient; 29 | private final ApiAuth apiAuth; 30 | private final String downloadId; 31 | 32 | public FileDownloadOperation( 33 | final HttpClient httpClient, final ApiAuth apiAuth, final String downloadId) { 34 | this.httpClient = httpClient; 35 | this.apiAuth = apiAuth; 36 | this.downloadId = downloadId; 37 | } 38 | 39 | @Override 40 | protected void invoke() { 41 | httpClient 42 | .request(GET, "/api/file/download?" + downloadIdQueryParam(downloadId)) 43 | .onSuccess( 44 | request -> { 45 | request.response().onSuccess(this::handle).onFailure(this::handleException); 46 | request.exceptionHandler(this::handleException); 47 | request.putHeader(COOKIE.toString(), apiAuth.getCookies()); 48 | request.end(); 49 | }) 50 | .onFailure(this::handleException); 51 | } 52 | 53 | @Override 54 | protected void handleResponseBuffer(final HttpClientResponse response, final Buffer buffer) { 55 | getResponseFuture().complete(buffer.toString(StandardCharsets.UTF_8)); 56 | } 57 | 58 | private String downloadIdQueryParam(final String downloadId) { 59 | return "id=" + URLEncoder.encode(downloadId, StandardCharsets.UTF_8); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /keystorage/interlock/src/main/java/tech/pegasys/signers/interlock/vertx/operations/LoginOperation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.interlock.vertx.operations; 14 | 15 | import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; 16 | import static io.vertx.core.http.HttpMethod.POST; 17 | 18 | import tech.pegasys.signers.interlock.model.ApiAuth; 19 | 20 | import java.util.List; 21 | 22 | import io.vertx.core.MultiMap; 23 | import io.vertx.core.http.HttpClient; 24 | import io.vertx.core.http.HttpHeaders; 25 | import io.vertx.core.json.JsonObject; 26 | 27 | public class LoginOperation extends AbstractOperation { 28 | private final HttpClient httpClient; 29 | private final String volume; 30 | private final String password; 31 | 32 | public LoginOperation(final HttpClient httpClient, final String volume, final String password) { 33 | this.httpClient = httpClient; 34 | this.volume = volume; 35 | this.password = password; 36 | } 37 | 38 | @Override 39 | protected void invoke() { 40 | final String body = 41 | new JsonObject() 42 | .put("volume", volume) 43 | .put("password", password) 44 | .put("dispose", false) 45 | .encode(); 46 | httpClient 47 | .request(POST, "/api/auth/login") 48 | .onSuccess( 49 | request -> { 50 | request.response().onSuccess(this::handle).onFailure(this::handleException); 51 | request.exceptionHandler(this::handleException); 52 | request.putHeader(CONTENT_TYPE, "application/json"); 53 | request.end(body); 54 | }) 55 | .onFailure(this::handleException); 56 | } 57 | 58 | @Override 59 | protected ApiAuth processJsonResponse(final JsonObject json, final MultiMap headers) { 60 | final String xsrfToken = json.getJsonObject("response").getString("XSRFToken"); 61 | final List cookies = headers.getAll(HttpHeaders.SET_COOKIE); 62 | return new ApiAuth(xsrfToken, cookies); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /keystorage/interlock/src/main/java/tech/pegasys/signers/interlock/vertx/operations/LogoutOperation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.interlock.vertx.operations; 14 | 15 | import static io.vertx.core.http.HttpHeaders.COOKIE; 16 | import static io.vertx.core.http.HttpMethod.POST; 17 | import static tech.pegasys.signers.interlock.model.ApiAuth.XSRF_TOKEN_HEADER; 18 | 19 | import tech.pegasys.signers.interlock.model.ApiAuth; 20 | 21 | import io.vertx.core.http.HttpClient; 22 | 23 | public class LogoutOperation extends AbstractOperation { 24 | private final HttpClient httpClient; 25 | private final ApiAuth apiAuth; 26 | 27 | public LogoutOperation(final HttpClient httpClient, final ApiAuth apiAuth) { 28 | this.httpClient = httpClient; 29 | this.apiAuth = apiAuth; 30 | } 31 | 32 | @Override 33 | protected void invoke() { 34 | httpClient 35 | .request(POST, "/api/auth/logout") 36 | .onSuccess( 37 | request -> { 38 | request.response().onSuccess(this::handle).onFailure(this::handleException); 39 | request.exceptionHandler(this::handleException); 40 | request.putHeader(XSRF_TOKEN_HEADER, apiAuth.getToken()); 41 | request.putHeader(COOKIE.toString(), apiAuth.getCookies()); 42 | request.end(); 43 | }) 44 | .onFailure(this::handleException); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /keystorage/interlock/src/test/resources/log4j2-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /keystorage/yubihsm2/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | 14 | apply plugin: 'java-library' 15 | 16 | jar { 17 | archiveBaseName = calculateJarName(project) 18 | manifest { 19 | attributes( 20 | 'Specification-Title': archiveBaseName.get(), 21 | 'Specification-Version': rootProject.version, 22 | 'Implementation-Title': archiveBaseName.get(), 23 | 'Implementation-Version': calculateVersion() 24 | ) 25 | } 26 | } 27 | 28 | dependencies { 29 | implementation 'org.apache.logging.log4j:log4j-api' 30 | implementation 'org.apache.tuweni:tuweni-bytes' 31 | implementation 'org.xipki.iaik:sunpkcs11-wrapper' 32 | 33 | runtimeOnly 'org.apache.logging.log4j:log4j-core' 34 | runtimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl' 35 | 36 | testImplementation 'org.assertj:assertj-core' 37 | testImplementation 'org.junit.jupiter:junit-jupiter-engine' 38 | testImplementation 'org.junit.jupiter:junit-jupiter-api' 39 | testImplementation 'org.junit.jupiter:junit-jupiter-params' 40 | 41 | errorprone("com.google.errorprone:error_prone_core") 42 | } 43 | -------------------------------------------------------------------------------- /keystorage/yubihsm2/src/main/java/tech/pegasys/signers/yubihsm/YubiHsm.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.yubihsm; 14 | 15 | import org.apache.tuweni.bytes.Bytes; 16 | 17 | public interface YubiHsm { 18 | 19 | /** 20 | * Fetch key as opaque data from YubiHSM 21 | * 22 | * @param opaqueObjId Opaque object id 23 | * @return data as Bytes 24 | * @throws YubiHsmException if unable to fetch data 25 | */ 26 | Bytes fetchOpaqueData(short opaqueObjId) throws YubiHsmException; 27 | } 28 | -------------------------------------------------------------------------------- /keystorage/yubihsm2/src/main/java/tech/pegasys/signers/yubihsm/YubiHsmException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.yubihsm; 14 | 15 | public class YubiHsmException extends RuntimeException { 16 | public YubiHsmException() { 17 | super(); 18 | } 19 | 20 | public YubiHsmException(final String message) { 21 | super(message); 22 | } 23 | 24 | public YubiHsmException(final String message, final Throwable cause) { 25 | super(message, cause); 26 | } 27 | 28 | public YubiHsmException(final Throwable cause) { 29 | super(cause); 30 | } 31 | 32 | protected YubiHsmException( 33 | final String message, 34 | final Throwable cause, 35 | final boolean enableSuppression, 36 | final boolean writableStackTrace) { 37 | super(message, cause, enableSuppression, writableStackTrace); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /keystorage/yubihsm2/src/main/java/tech/pegasys/signers/yubihsm/pkcs11/ExtendedData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.yubihsm.pkcs11; 14 | 15 | import iaik.pkcs.pkcs11.objects.Attribute; 16 | import iaik.pkcs.pkcs11.objects.ByteArrayAttribute; 17 | import iaik.pkcs.pkcs11.objects.Data; 18 | import org.apache.tuweni.bytes.Bytes; 19 | 20 | /** Extends Data to provide support for ID (for findObjectInit) which is used by YubiHSM */ 21 | class ExtendedData extends Data { 22 | 23 | public ExtendedData(final short opaqueObjId) { 24 | super(); 25 | // The ID (CKA_ID) attribute - used by YubiHSM PKCS11 module. 26 | final ByteArrayAttribute id = new ByteArrayAttribute(Attribute.ID); 27 | id.setByteArrayValue(Bytes.ofUnsignedShort(opaqueObjId).toArrayUnsafe()); 28 | attributeTable.put(Attribute.ID, id); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /keystorage/yubihsm2/src/main/java/tech/pegasys/signers/yubihsm/pkcs11/Pkcs11Session.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.yubihsm.pkcs11; 14 | 15 | import tech.pegasys.signers.yubihsm.YubiHsmException; 16 | 17 | import iaik.pkcs.pkcs11.Session; 18 | import iaik.pkcs.pkcs11.TokenException; 19 | import iaik.pkcs.pkcs11.objects.Attribute; 20 | import iaik.pkcs.pkcs11.objects.ByteArrayAttribute; 21 | import iaik.pkcs.pkcs11.objects.PKCS11Object; 22 | import org.apache.logging.log4j.LogManager; 23 | import org.apache.logging.log4j.Logger; 24 | 25 | /** Wrapper around PKCS11 session. */ 26 | public class Pkcs11Session implements AutoCloseable { 27 | private static final Logger LOG = LogManager.getLogger(); 28 | 29 | private final Session session; 30 | 31 | Pkcs11Session(final Session session) { 32 | this.session = session; 33 | } 34 | 35 | void initFind(PKCS11Object searchTemplate) { 36 | try { 37 | session.findObjectsInit(searchTemplate); 38 | } catch (final TokenException e) { 39 | throw new YubiHsmException("Find Initialization failed", e); 40 | } 41 | } 42 | 43 | byte[] findData() { 44 | try { 45 | final PKCS11Object[] data = session.findObjects(1); 46 | if (data == null || data.length == 0) { 47 | throw new YubiHsmException("Data not found"); 48 | } 49 | 50 | return ((ByteArrayAttribute) data[0].getAttributeTable().get(Attribute.VALUE)) 51 | .getByteArrayValue(); 52 | } catch (final TokenException e) { 53 | throw new YubiHsmException("Data not found", e); 54 | } 55 | } 56 | 57 | void finalizeFind() { 58 | LOG.trace("Find Objects Final"); 59 | try { 60 | session.findObjectsFinal(); 61 | } catch (final TokenException e) { 62 | LOG.warn("PKCS11 Find finalize failed {}", e.getMessage()); 63 | } 64 | } 65 | 66 | @Override 67 | public void close() { 68 | if (session != null) { 69 | logoutSession(session); 70 | closeSession(session); 71 | } 72 | } 73 | 74 | static void closeSession(final Session session) { 75 | try { 76 | session.closeSession(); 77 | } catch (final TokenException closeTokenException) { 78 | LOG.warn("Unable to close session: " + closeTokenException.getMessage()); 79 | } 80 | } 81 | 82 | static void logoutSession(final Session session) { 83 | try { 84 | session.logout(); 85 | } catch (final TokenException e) { 86 | LOG.warn("Unable to logout session: " + e.getMessage()); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /keystorage/yubihsm2/src/main/java/tech/pegasys/signers/yubihsm/pkcs11/Pkcs11YubiHsm.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.yubihsm.pkcs11; 14 | 15 | import tech.pegasys.signers.yubihsm.YubiHsm; 16 | import tech.pegasys.signers.yubihsm.YubiHsmException; 17 | 18 | import org.apache.logging.log4j.LogManager; 19 | import org.apache.logging.log4j.Logger; 20 | import org.apache.tuweni.bytes.Bytes; 21 | 22 | public class Pkcs11YubiHsm implements YubiHsm { 23 | private static final Logger LOG = LogManager.getLogger(); 24 | 25 | private final Pkcs11Session session; 26 | 27 | public Pkcs11YubiHsm(final Pkcs11Session pkcs11Session) { 28 | this.session = pkcs11Session; 29 | } 30 | 31 | @Override 32 | public synchronized Bytes fetchOpaqueData(final short opaqueObjId) throws YubiHsmException { 33 | LOG.debug("Fetching data for Opaque id {}", opaqueObjId); 34 | try { 35 | session.initFind(new ExtendedData(opaqueObjId)); 36 | return Bytes.wrap(session.findData()); 37 | } finally { 38 | session.finalizeFind(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /keystorage/yubihsm2/src/main/java/tech/pegasys/signers/yubihsm/pkcs11/Pkcs11YubiHsmPin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.yubihsm.pkcs11; 14 | 15 | public class Pkcs11YubiHsmPin { 16 | private final char[] pin; 17 | 18 | public Pkcs11YubiHsmPin(final short authId, final String password) { 19 | this.pin = String.format("%04X%s", authId, password).toCharArray(); 20 | } 21 | 22 | public char[] getPin() { 23 | return pin; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /keystorage/yubihsm2/src/test/resources/log4j2-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | 14 | rootProject.name='signers' 15 | include 'bls-keystore' 16 | include 'keystorage:common' 17 | include 'keystorage:hashicorp' 18 | include 'keystorage:azure' 19 | include 'keystorage:yubihsm2' 20 | include 'keystorage:interlock' 21 | include 'keystorage:aws' 22 | include 'acceptance-tests' 23 | include 'signing:secp256k1:api' 24 | include 'signing:secp256k1:impl' 25 | -------------------------------------------------------------------------------- /signing/build.gradle: -------------------------------------------------------------------------------- 1 | jar { enabled = false } 2 | -------------------------------------------------------------------------------- /signing/secp256k1/api/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | 14 | jar { 15 | archiveBaseName = calculateJarName(project) 16 | manifest { 17 | attributes( 18 | 'Specification-Title': archiveBaseName, 19 | 'Specification-Version': project.version, 20 | 'Implementation-Title': archiveBaseName, 21 | 'Implementation-Version': calculateVersion() 22 | ) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /signing/secp256k1/api/src/main/java/tech/pegasys/signers/secp256k1/api/FileSelector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.api; 14 | 15 | import java.nio.file.DirectoryStream.Filter; 16 | import java.nio.file.Path; 17 | 18 | /* 19 | A set of rules regarding how key files are to be selected. 20 | Should be overridden by the calling application to define their naming 21 | convention. 22 | */ 23 | public interface FileSelector { 24 | Filter getConfigFilesFilter(T selectionCriteria); 25 | } 26 | -------------------------------------------------------------------------------- /signing/secp256k1/api/src/main/java/tech/pegasys/signers/secp256k1/api/Signature.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.api; 14 | 15 | import java.math.BigInteger; 16 | 17 | public class Signature { 18 | private final BigInteger v; 19 | private final BigInteger r; 20 | private final BigInteger s; 21 | 22 | public Signature(final BigInteger v, final BigInteger r, final BigInteger s) { 23 | this.v = v; 24 | this.r = r; 25 | this.s = s; 26 | } 27 | 28 | public BigInteger getV() { 29 | return v; 30 | } 31 | 32 | public BigInteger getR() { 33 | return r; 34 | } 35 | 36 | public BigInteger getS() { 37 | return s; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /signing/secp256k1/api/src/main/java/tech/pegasys/signers/secp256k1/api/Signer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.api; 14 | 15 | import java.security.interfaces.ECPublicKey; 16 | 17 | public interface Signer { 18 | 19 | Signature sign(final byte[] data); 20 | 21 | ECPublicKey getPublicKey(); 22 | } 23 | -------------------------------------------------------------------------------- /signing/secp256k1/api/src/main/java/tech/pegasys/signers/secp256k1/api/SignerIdentifier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.api; 14 | 15 | import java.security.interfaces.ECPublicKey; 16 | 17 | public interface SignerIdentifier { 18 | String toStringIdentifier(); 19 | 20 | boolean validate(ECPublicKey publicKey); 21 | } 22 | -------------------------------------------------------------------------------- /signing/secp256k1/api/src/main/java/tech/pegasys/signers/secp256k1/api/SignerProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.api; 14 | 15 | import java.security.interfaces.ECPublicKey; 16 | import java.util.Optional; 17 | import java.util.Set; 18 | import java.util.function.Function; 19 | 20 | public interface SignerProvider { 21 | 22 | Optional getSigner(SignerIdentifier publicKey); 23 | 24 | Set availablePublicKeys(Function identifierFunction); 25 | 26 | default void shutdown() {} 27 | } 28 | -------------------------------------------------------------------------------- /signing/secp256k1/api/src/main/java/tech/pegasys/signers/secp256k1/api/SingleSignerProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.api; 14 | 15 | import java.security.interfaces.ECPublicKey; 16 | import java.util.Collections; 17 | import java.util.Optional; 18 | import java.util.Set; 19 | import java.util.function.Function; 20 | 21 | public class SingleSignerProvider implements SignerProvider { 22 | 23 | private final Signer signer; 24 | 25 | public SingleSignerProvider(final Signer signer) { 26 | if (signer == null) { 27 | throw new IllegalArgumentException("SingleSignerFactory requires a non-null Signer"); 28 | } 29 | this.signer = signer; 30 | } 31 | 32 | @Override 33 | public Optional getSigner(final SignerIdentifier signerIdentifier) { 34 | if (signerIdentifier == null) { 35 | return Optional.empty(); 36 | } 37 | 38 | return signerIdentifier.validate(signer.getPublicKey()) 39 | ? Optional.of(signer) 40 | : Optional.empty(); 41 | } 42 | 43 | @Override 44 | public Set availablePublicKeys( 45 | final Function identifierFunction) { 46 | return signer.getPublicKey() != null ? Set.of(signer.getPublicKey()) : Collections.emptySet(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /signing/secp256k1/api/src/main/java/tech/pegasys/signers/secp256k1/api/util/AddressUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.api.util; 14 | 15 | import java.util.Locale; 16 | 17 | public class AddressUtil { 18 | public static String remove0xPrefix(final String address) { 19 | if (address == null) { 20 | return null; 21 | } 22 | 23 | return address.toLowerCase(Locale.US).startsWith("0x") ? address.substring(2) : address; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /signing/secp256k1/build.gradle: -------------------------------------------------------------------------------- 1 | jar { enabled = false } 2 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | 14 | apply plugin: 'java-library' 15 | apply plugin: 'java-test-fixtures' 16 | 17 | jar { 18 | archiveBaseName = calculateJarName(project) 19 | manifest { 20 | attributes( 21 | 'Specification-Title': archiveBaseName.get(), 22 | 'Specification-Version': rootProject.version, 23 | 'Implementation-Title': archiveBaseName.get(), 24 | 'Implementation-Version': calculateVersion() 25 | ) 26 | } 27 | } 28 | 29 | testFixturesJar { 30 | archiveBaseName = calculateJarName(project) 31 | } 32 | 33 | dependencies { 34 | 35 | implementation project(':signing:secp256k1:api') 36 | implementation project(':keystorage:hashicorp') 37 | implementation project(':keystorage:azure') 38 | 39 | implementation 'com.google.guava:guava' 40 | implementation 'io.vertx:vertx-core' 41 | implementation 'org.apache.logging.log4j:log4j-api' 42 | implementation 'org.apache.logging.log4j:log4j-core' 43 | implementation 'org.apache.tuweni:tuweni-net' 44 | implementation 'org.apache.tuweni:tuweni-toml' 45 | implementation 'org.web3j:core' 46 | implementation 'com.azure:azure-security-keyvault-keys' 47 | 48 | runtimeOnly 'com.squareup.okhttp3:okhttp' 49 | runtimeOnly 'org.apache.logging.log4j:log4j-core' 50 | runtimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl' 51 | 52 | testImplementation 'org.junit.jupiter:junit-jupiter-api' 53 | testImplementation 'org.junit.jupiter:junit-jupiter-params' 54 | testImplementation 'org.assertj:assertj-core' 55 | testImplementation 'org.mockito:mockito-inline' 56 | testImplementation 'org.mockito:mockito-core' 57 | testImplementation 'org.mockito:mockito-junit-jupiter' 58 | testImplementation(testFixtures(project(":keystorage:hashicorp"))) 59 | 60 | testImplementation 'com.azure:azure-security-keyvault-keys' 61 | testImplementation 'com.azure:azure-identity' 62 | 63 | testFixturesImplementation project(':signing:secp256k1:api') 64 | testFixturesImplementation 'org.apache.tuweni:tuweni-bytes' 65 | 66 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' 67 | } 68 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/common/PasswordFileUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.common; 14 | 15 | import static java.nio.charset.StandardCharsets.UTF_8; 16 | 17 | import java.io.IOException; 18 | import java.nio.file.Path; 19 | import java.util.Optional; 20 | 21 | import com.google.common.io.Files; 22 | 23 | public class PasswordFileUtil { 24 | 25 | /** 26 | * Read password from the first line of specified file 27 | * 28 | * @param path The file to read the password from 29 | * @return Password 30 | * @throws IOException For file operations 31 | * @throws SignerInitializationException If password file is empty 32 | */ 33 | public static String readPasswordFromFile(final Path path) throws IOException { 34 | return Optional.ofNullable(Files.asCharSource(path.toFile(), UTF_8).readFirstLine()).orElse(""); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/common/SignerInitializationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.common; 14 | 15 | public class SignerInitializationException extends RuntimeException { 16 | public SignerInitializationException() { 17 | super(); 18 | } 19 | 20 | public SignerInitializationException(final String message) { 21 | super(message); 22 | } 23 | 24 | public SignerInitializationException(final String message, final Throwable e) { 25 | super(message, e); 26 | } 27 | 28 | public SignerInitializationException(final Throwable e) { 29 | super(e); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/filebased/CredentialSigner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.filebased; 14 | 15 | import tech.pegasys.signers.secp256k1.EthPublicKeyUtils; 16 | import tech.pegasys.signers.secp256k1.api.Signature; 17 | import tech.pegasys.signers.secp256k1.api.Signer; 18 | 19 | import java.math.BigInteger; 20 | import java.security.interfaces.ECPublicKey; 21 | 22 | import org.web3j.crypto.Credentials; 23 | import org.web3j.crypto.Sign; 24 | import org.web3j.crypto.Sign.SignatureData; 25 | 26 | public class CredentialSigner implements Signer { 27 | 28 | private final Credentials credentials; 29 | private final ECPublicKey publicKey; 30 | private final boolean needToHash; 31 | 32 | public CredentialSigner(final Credentials credentials, final boolean needToHash) { 33 | this.credentials = credentials; 34 | this.publicKey = EthPublicKeyUtils.createPublicKey(credentials.getEcKeyPair().getPublicKey()); 35 | this.needToHash = needToHash; 36 | } 37 | 38 | public CredentialSigner(final Credentials credentials) { 39 | this(credentials, true); 40 | } 41 | 42 | @Override 43 | public Signature sign(final byte[] data) { 44 | final SignatureData signature = Sign.signMessage(data, credentials.getEcKeyPair(), needToHash); 45 | return new Signature( 46 | new BigInteger(signature.getV()), 47 | new BigInteger(1, signature.getR()), 48 | new BigInteger(1, signature.getS())); 49 | } 50 | 51 | @Override 52 | public ECPublicKey getPublicKey() { 53 | return publicKey; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/filebased/FileBasedSignerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.filebased; 14 | 15 | import static tech.pegasys.signers.secp256k1.common.PasswordFileUtil.readPasswordFromFile; 16 | 17 | import tech.pegasys.signers.secp256k1.api.Signer; 18 | import tech.pegasys.signers.secp256k1.common.SignerInitializationException; 19 | 20 | import java.io.FileNotFoundException; 21 | import java.io.IOException; 22 | import java.nio.file.Path; 23 | 24 | import org.apache.logging.log4j.LogManager; 25 | import org.apache.logging.log4j.Logger; 26 | import org.web3j.crypto.CipherException; 27 | import org.web3j.crypto.Credentials; 28 | import org.web3j.crypto.WalletUtils; 29 | 30 | public class FileBasedSignerFactory { 31 | 32 | private static final Logger LOG = LogManager.getLogger(); 33 | private static final String READ_PWD_FILE_MESSAGE = "Error when reading the password from file. "; 34 | private static final String READ_AUTH_FILE_MESSAGE = 35 | "Error when reading key file for the file based signer. "; 36 | private static final String DECRYPTING_KEY_FILE_MESSAGE = 37 | "Error when decrypting key for the file based signer. "; 38 | 39 | public static Signer createSigner(final FileSignerConfig signerConfig) { 40 | return createSigner(signerConfig.getKeystoreFile(), signerConfig.getKeystorePasswordFile()); 41 | } 42 | 43 | public static Signer createSigner(final Path keyFilePath, final Path passwordFilePath) { 44 | final String password; 45 | try { 46 | password = readPasswordFromFile(passwordFilePath); 47 | } catch (final FileNotFoundException fnfe) { 48 | LOG.error("File not found: " + passwordFilePath); 49 | throw new SignerInitializationException("File not found: " + passwordFilePath); 50 | } catch (final IOException e) { 51 | final String message = READ_PWD_FILE_MESSAGE; 52 | LOG.error(message, e); 53 | throw new SignerInitializationException(message, e); 54 | } 55 | try { 56 | final Credentials credentials = WalletUtils.loadCredentials(password, keyFilePath.toFile()); 57 | return new CredentialSigner(credentials); 58 | } catch (final IOException e) { 59 | final String message = READ_AUTH_FILE_MESSAGE + keyFilePath.toString(); 60 | LOG.error(message, e); 61 | throw new SignerInitializationException(message, e); 62 | } catch (final CipherException e) { 63 | final String message = DECRYPTING_KEY_FILE_MESSAGE; 64 | LOG.error(message, e); 65 | throw new SignerInitializationException(message, e); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/filebased/FileSignerConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.filebased; 14 | 15 | import java.nio.file.Path; 16 | import java.util.Objects; 17 | 18 | public class FileSignerConfig { 19 | 20 | private final Path keystoreFile; 21 | private final Path keystorePasswordFile; 22 | 23 | public FileSignerConfig(final Path keystoreFile, Path keystorePasswordFile) { 24 | this.keystoreFile = keystoreFile; 25 | this.keystorePasswordFile = keystorePasswordFile; 26 | } 27 | 28 | public Path getKeystoreFile() { 29 | return keystoreFile; 30 | } 31 | 32 | public Path getKeystorePasswordFile() { 33 | return keystorePasswordFile; 34 | } 35 | 36 | @Override 37 | public boolean equals(Object o) { 38 | if (this == o) { 39 | return true; 40 | } 41 | if (o == null || getClass() != o.getClass()) { 42 | return false; 43 | } 44 | final FileSignerConfig that = (FileSignerConfig) o; 45 | return Objects.equals(keystoreFile, that.keystoreFile) 46 | && Objects.equals(keystorePasswordFile, that.keystorePasswordFile); 47 | } 48 | 49 | @Override 50 | public int hashCode() { 51 | return Objects.hash(keystoreFile, keystorePasswordFile); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/hashicorp/HashicorpSignerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.hashicorp; 14 | 15 | import tech.pegasys.signers.hashicorp.HashicorpConnection; 16 | import tech.pegasys.signers.hashicorp.HashicorpConnectionFactory; 17 | import tech.pegasys.signers.hashicorp.HashicorpException; 18 | import tech.pegasys.signers.hashicorp.config.HashicorpKeyConfig; 19 | import tech.pegasys.signers.secp256k1.api.Signer; 20 | import tech.pegasys.signers.secp256k1.common.SignerInitializationException; 21 | import tech.pegasys.signers.secp256k1.filebased.CredentialSigner; 22 | 23 | import org.web3j.crypto.Credentials; 24 | 25 | public class HashicorpSignerFactory { 26 | 27 | public HashicorpSignerFactory() {} 28 | 29 | public Signer create(final HashicorpKeyConfig keyConfig) { 30 | try (final HashicorpConnectionFactory connectionFactory = new HashicorpConnectionFactory()) { 31 | final HashicorpConnection connection = 32 | connectionFactory.create(keyConfig.getConnectionParams()); 33 | final String secret = connection.fetchKey(keyConfig.getKeyDefinition()); 34 | final Credentials credentials = Credentials.create(secret); 35 | return new CredentialSigner(credentials); 36 | } catch (final HashicorpException e) { 37 | throw new SignerInitializationException("Failed to extract secret from Hashicorp vault.", e); 38 | } 39 | } 40 | 41 | public void shutdown() {} 42 | } 43 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/multikey/MultiSignerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.multikey; 14 | 15 | import tech.pegasys.signers.secp256k1.api.Signer; 16 | import tech.pegasys.signers.secp256k1.multikey.metadata.AzureSigningMetadataFile; 17 | import tech.pegasys.signers.secp256k1.multikey.metadata.FileBasedSigningMetadataFile; 18 | import tech.pegasys.signers.secp256k1.multikey.metadata.HashicorpSigningMetadataFile; 19 | import tech.pegasys.signers.secp256k1.multikey.metadata.RawSigningMetadataFile; 20 | 21 | public interface MultiSignerFactory { 22 | 23 | Signer createSigner(AzureSigningMetadataFile metadataFile); 24 | 25 | Signer createSigner(FileBasedSigningMetadataFile metadataFile); 26 | 27 | Signer createSigner(HashicorpSigningMetadataFile metadataFile); 28 | 29 | Signer createSigner(RawSigningMetadataFile metadataFile); 30 | } 31 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/multikey/SignerType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.multikey; 14 | 15 | public enum SignerType { 16 | FILE_BASED_SIGNER("file-based-signer"), 17 | AZURE_SIGNER("azure-signer"), 18 | HASHICORP_SIGNER("hashicorp-signer"), 19 | RAW_SIGNER("raw-signer"), 20 | UNKNOWN_TYPE_SIGNER("unknown"); 21 | 22 | private final String type; 23 | 24 | SignerType(String type) { 25 | this.type = type; 26 | } 27 | 28 | private String getType() { 29 | return type; 30 | } 31 | 32 | public static SignerType fromString(final String typeString) { 33 | for (final SignerType signerType : SignerType.values()) { 34 | if (signerType.getType().equals(typeString)) { 35 | return signerType; 36 | } 37 | } 38 | return UNKNOWN_TYPE_SIGNER; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/multikey/TomlConfigFileParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.multikey; 14 | 15 | import static java.nio.charset.StandardCharsets.UTF_8; 16 | 17 | import java.io.File; 18 | import java.io.IOException; 19 | import java.util.stream.Collectors; 20 | 21 | import com.google.common.io.Resources; 22 | import org.apache.tuweni.toml.Toml; 23 | import org.apache.tuweni.toml.TomlParseError; 24 | import org.apache.tuweni.toml.TomlParseResult; 25 | 26 | public class TomlConfigFileParser { 27 | 28 | private static TomlParseResult loadConfiguration(final String toml) throws RuntimeException { 29 | final TomlParseResult result = Toml.parse(toml); 30 | 31 | if (result == null || result.isEmpty()) { 32 | throw new RuntimeException("Empty TOML result: " + toml); 33 | } 34 | 35 | if (result.hasErrors()) { 36 | final String errors = 37 | result.errors().stream().map(TomlParseError::toString).collect(Collectors.joining("\n")); 38 | throw new RuntimeException("Invalid TOML configuration: \n" + errors); 39 | } 40 | return result; 41 | } 42 | 43 | public static TomlParseResult loadConfigurationFromFile(final String configFilePath) 44 | throws IOException { 45 | return loadConfiguration(configTomlAsString(new File(configFilePath))); 46 | } 47 | 48 | private static String configTomlAsString(final File file) throws IOException { 49 | return Resources.toString(file.toURI().toURL(), UTF_8); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/multikey/TomlTableAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.multikey; 14 | 15 | import java.util.Optional; 16 | 17 | import org.apache.tuweni.toml.TomlTable; 18 | 19 | public class TomlTableAdapter { 20 | 21 | private final TomlTable table; 22 | 23 | public TomlTableAdapter(final TomlTable table) { 24 | this.table = table; 25 | } 26 | 27 | public String getString(final String key) { 28 | return Optional.ofNullable(table.getString(key)) 29 | .orElseThrow(() -> new IllegalArgumentException(key + " was not specified in TOML input.")); 30 | } 31 | 32 | public Long getLong(final String key) { 33 | return Optional.ofNullable(table.getLong(key)) 34 | .orElseThrow(() -> new IllegalArgumentException(key + " was not specified in TOML input.")); 35 | } 36 | 37 | public Optional getOptionalString(final String key) { 38 | return Optional.ofNullable(table.getString(key)); 39 | } 40 | 41 | public Optional getOptionalBoolean(final String key) { 42 | return Optional.ofNullable(table.getBoolean(key)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/multikey/metadata/AzureSigningMetadataFile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.multikey.metadata; 14 | 15 | import tech.pegasys.signers.secp256k1.api.Signer; 16 | import tech.pegasys.signers.secp256k1.azure.AzureConfig; 17 | import tech.pegasys.signers.secp256k1.multikey.MultiSignerFactory; 18 | 19 | public class AzureSigningMetadataFile extends SigningMetadataFile { 20 | 21 | private final AzureConfig config; 22 | 23 | public AzureSigningMetadataFile(final String filename, final AzureConfig config) { 24 | super(filename); 25 | this.config = config; 26 | } 27 | 28 | public AzureConfig getConfig() { 29 | return config; 30 | } 31 | 32 | @Override 33 | public Signer createSigner(final MultiSignerFactory factory) { 34 | return factory.createSigner(this); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/multikey/metadata/FileBasedSigningMetadataFile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.multikey.metadata; 14 | 15 | import tech.pegasys.signers.secp256k1.api.Signer; 16 | import tech.pegasys.signers.secp256k1.filebased.FileSignerConfig; 17 | import tech.pegasys.signers.secp256k1.multikey.MultiSignerFactory; 18 | 19 | import com.google.common.base.Objects; 20 | 21 | public class FileBasedSigningMetadataFile extends SigningMetadataFile { 22 | 23 | private final FileSignerConfig config; 24 | 25 | public FileBasedSigningMetadataFile(final String filename, final FileSignerConfig config) { 26 | super(filename); 27 | this.config = config; 28 | } 29 | 30 | public FileSignerConfig getConfig() { 31 | return config; 32 | } 33 | 34 | @Override 35 | public boolean equals(final Object o) { 36 | if (this == o) { 37 | return true; 38 | } 39 | if (o == null || getClass() != o.getClass()) { 40 | return false; 41 | } 42 | final FileBasedSigningMetadataFile that = (FileBasedSigningMetadataFile) o; 43 | return Objects.equal(filename, that.filename) && Objects.equal(config, that.config); 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return Objects.hashCode(filename, config); 49 | } 50 | 51 | @Override 52 | public Signer createSigner(final MultiSignerFactory factory) { 53 | return factory.createSigner(this); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/multikey/metadata/HashicorpSigningMetadataFile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.multikey.metadata; 14 | 15 | import tech.pegasys.signers.hashicorp.config.HashicorpKeyConfig; 16 | import tech.pegasys.signers.secp256k1.api.Signer; 17 | import tech.pegasys.signers.secp256k1.multikey.MultiSignerFactory; 18 | 19 | public class HashicorpSigningMetadataFile extends SigningMetadataFile { 20 | 21 | private final HashicorpKeyConfig hashicorpConfig; 22 | 23 | public HashicorpSigningMetadataFile( 24 | final String filename, final HashicorpKeyConfig hashicorpConfig) { 25 | super(filename); 26 | this.hashicorpConfig = hashicorpConfig; 27 | } 28 | 29 | public HashicorpKeyConfig getConfig() { 30 | return hashicorpConfig; 31 | } 32 | 33 | @Override 34 | public Signer createSigner(final MultiSignerFactory factory) { 35 | return factory.createSigner(this); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/multikey/metadata/RawSigningMetadataFile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.multikey.metadata; 14 | 15 | import tech.pegasys.signers.secp256k1.api.Signer; 16 | import tech.pegasys.signers.secp256k1.multikey.MultiSignerFactory; 17 | 18 | public class RawSigningMetadataFile extends SigningMetadataFile { 19 | 20 | private final String privKey; 21 | 22 | public RawSigningMetadataFile(final String filename, final String privKey) { 23 | super(filename); 24 | this.privKey = privKey; 25 | } 26 | 27 | @Override 28 | public Signer createSigner(final MultiSignerFactory factory) { 29 | return factory.createSigner(this); 30 | } 31 | 32 | public String getPrivKey() { 33 | return privKey; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/main/java/tech/pegasys/signers/secp256k1/multikey/metadata/SigningMetadataFile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.multikey.metadata; 14 | 15 | import tech.pegasys.signers.secp256k1.api.Signer; 16 | import tech.pegasys.signers.secp256k1.multikey.MultiSignerFactory; 17 | 18 | public abstract class SigningMetadataFile { 19 | 20 | protected String filename; 21 | 22 | public SigningMetadataFile(final String filename) { 23 | this.filename = filename; 24 | } 25 | 26 | public String getFilename() { 27 | return filename; 28 | } 29 | 30 | public abstract Signer createSigner(final MultiSignerFactory factory); 31 | } 32 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/java/tech/pegasys/signers/secp256k1/common/PasswordFileUtilTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.common; 14 | 15 | import static java.nio.charset.StandardCharsets.UTF_8; 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | 18 | import java.io.IOException; 19 | import java.nio.file.Files; 20 | import java.nio.file.Path; 21 | 22 | import org.junit.jupiter.api.Test; 23 | import org.junit.jupiter.api.io.TempDir; 24 | import org.junit.jupiter.params.ParameterizedTest; 25 | import org.junit.jupiter.params.provider.ValueSource; 26 | 27 | class PasswordFileUtilTest { 28 | 29 | @ParameterizedTest 30 | @ValueSource(strings = {"line1\nline2", "line1\n", "line1"}) 31 | void canReadPasswordFromFile(final String content, @TempDir final Path tempDir) 32 | throws IOException { 33 | final Path passwordFile = Files.write(tempDir.resolve("password.txt"), content.getBytes(UTF_8)); 34 | assertThat(PasswordFileUtil.readPasswordFromFile(passwordFile)).isEqualTo("line1"); 35 | } 36 | 37 | @Test 38 | void canReadSpaceOnlyPasswordFromFile(@TempDir final Path tempDir) throws IOException { 39 | final Path passwordFile = Files.write(tempDir.resolve("password.txt"), " \n".getBytes(UTF_8)); 40 | assertThat(PasswordFileUtil.readPasswordFromFile(passwordFile)).isEqualTo(" "); 41 | } 42 | 43 | @ParameterizedTest 44 | @ValueSource(strings = {"", "\n"}) 45 | void canReadPasswordFromEmptyStringFile(final String content, @TempDir final Path tempDir) 46 | throws IOException { 47 | final Path passwordFile = Files.write(tempDir.resolve("password.txt"), content.getBytes(UTF_8)); 48 | assertThat(PasswordFileUtil.readPasswordFromFile(passwordFile)).isEqualTo(""); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/java/tech/pegasys/signers/secp256k1/filebased/CredentialSignerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.filebased; 14 | 15 | import static java.nio.charset.StandardCharsets.UTF_8; 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | 18 | import java.math.BigInteger; 19 | 20 | import org.junit.jupiter.api.Test; 21 | import org.web3j.crypto.Credentials; 22 | import org.web3j.crypto.ECKeyPair; 23 | import org.web3j.crypto.Hash; 24 | 25 | class CredentialSignerTest { 26 | 27 | @Test 28 | void needToHashFlagAffectsProducedSignature() { 29 | final Credentials credentials = Credentials.create(ECKeyPair.create(BigInteger.ONE)); 30 | 31 | final CredentialSigner hashingSigner = new CredentialSigner(credentials); 32 | final CredentialSigner nonHashingSigner = new CredentialSigner(credentials, false); 33 | 34 | final byte[] data = "Hello World".getBytes(UTF_8); 35 | 36 | assertThat(hashingSigner.getPublicKey().getEncoded()) 37 | .isEqualTo(nonHashingSigner.getPublicKey().getEncoded()); 38 | assertThat(hashingSigner.sign(data)) 39 | .isEqualToComparingFieldByField(nonHashingSigner.sign(Hash.sha3(data))); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/java/tech/pegasys/signers/secp256k1/multikey/FileBasedSigningMetadataFileTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.multikey; 14 | 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | import static tech.pegasys.signers.secp256k1.multikey.MetadataFileFixture.CONFIG_FILE_EXTENSION; 17 | import static tech.pegasys.signers.secp256k1.multikey.MetadataFileFixture.KEY_FILE; 18 | import static tech.pegasys.signers.secp256k1.multikey.MetadataFileFixture.LOWERCASE_ADDRESS; 19 | import static tech.pegasys.signers.secp256k1.multikey.MetadataFileFixture.PASSWORD_FILE; 20 | import static tech.pegasys.signers.secp256k1.multikey.MetadataFileFixture.PREFIX_ADDRESS; 21 | import static tech.pegasys.signers.secp256k1.multikey.MetadataFileFixture.load; 22 | 23 | import tech.pegasys.signers.secp256k1.multikey.metadata.FileBasedSigningMetadataFile; 24 | 25 | import org.junit.jupiter.api.Test; 26 | 27 | class FileBasedSigningMetadataFileTest { 28 | 29 | @Test 30 | void matchingMetadataFileWithoutPrefixShouldHaveExpectedName() { 31 | final FileBasedSigningMetadataFile fileBasedSigningMetadataFile = 32 | load(LOWERCASE_ADDRESS + CONFIG_FILE_EXTENSION, KEY_FILE, PASSWORD_FILE); 33 | 34 | assertThat(fileBasedSigningMetadataFile.getFilename()) 35 | .matches(LOWERCASE_ADDRESS + CONFIG_FILE_EXTENSION); 36 | assertThat(fileBasedSigningMetadataFile.getConfig().getKeystoreFile().toFile().toString()) 37 | .matches(KEY_FILE); 38 | assertThat( 39 | fileBasedSigningMetadataFile.getConfig().getKeystorePasswordFile().toFile().toString()) 40 | .matches(PASSWORD_FILE); 41 | } 42 | 43 | @Test 44 | void matchingMetadataFileWithPrefixShouldHaveExpectedName() { 45 | final String prefix = "bar_"; 46 | final FileBasedSigningMetadataFile fileBasedSigningMetadataFile = 47 | load(prefix + PREFIX_ADDRESS + CONFIG_FILE_EXTENSION, KEY_FILE, PASSWORD_FILE); 48 | 49 | assertThat(fileBasedSigningMetadataFile.getFilename()) 50 | .matches(prefix + PREFIX_ADDRESS + CONFIG_FILE_EXTENSION); 51 | assertThat(fileBasedSigningMetadataFile.getConfig().getKeystoreFile().toFile().toString()) 52 | .matches(KEY_FILE); 53 | assertThat( 54 | fileBasedSigningMetadataFile.getConfig().getKeystorePasswordFile().toFile().toString()) 55 | .matches(PASSWORD_FILE); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/627306090abab3a6e1400e9345bc60c78a8bef57.toml: -------------------------------------------------------------------------------- 1 | [metadata] 2 | createdAt = 1994-11-05T08:15:30-05:00 3 | description = "Example of File based configuration" 4 | 5 | [signing] 6 | type = "file-based-signer" 7 | key-file = "/path/to/k.key" 8 | password-file = "/path/to/p.password" 9 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/UTC--2019-10-23T04-00-04.860366000Z--f17f52151ebef6c7334fad080c5704d77216b732.toml: -------------------------------------------------------------------------------- 1 | [metadata] 2 | createdAt = 1994-11-05T08:15:30-05:00 3 | description = "Example of File based configuration" 4 | 5 | [signing] 6 | type = "file-based-signer" 7 | key-file = "/path/to/k.key" 8 | password-file = "/path/to/p.password" 9 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/azureconfig.toml: -------------------------------------------------------------------------------- 1 | [metadata] 2 | createdAt = 2011-11-01T12:15:30Z 3 | description = "Example of Azure Key Vault based configuration" 4 | 5 | [signing] 6 | type = "azure-signer" 7 | key-vault-name = "testkey" 8 | key-name = "TestKey" 9 | key-version = "7c01fe58d68148bba5824ce418241092" 10 | client-id = "theClientId" 11 | client-secret = "theClientSecret" 12 | tenant-id = "theTenantId" 13 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/azureconfig_illegalValueType.toml: -------------------------------------------------------------------------------- 1 | [metadata] 2 | createdAt = 2011-11-01T12:15:30Z 3 | description = "Example of Azure Key Vault based configuration" 4 | 5 | [signing] 6 | type = "azure-signer" 7 | key-vault-name = 9 8 | key-name = "TestKey" 9 | key-version = "7c01fe58d68148bba5824ce418241092" 10 | client-id = "theClientId" 11 | client-secret = "theClientSecret" 12 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/azureconfig_missingField.toml: -------------------------------------------------------------------------------- 1 | [metadata] 2 | createdAt = 2011-11-01T12:15:30Z 3 | description = "Example of Azure Key Vault based configuration" 4 | 5 | [signing] 6 | type = "azure-signer" 7 | key-name = "TestKey" 8 | key-version = "7c01fe58d68148bba5824ce418241092" 9 | client-id = "theClientId" 10 | client-secret = "theClientSecret" 11 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/bar_fe3b557e8fb62b89f4916b721be55ceb828dbd73.toml: -------------------------------------------------------------------------------- 1 | [metadata] 2 | createdAt = 1994-11-05T08:15:30-05:00 3 | description = "Example of File based configuration" 4 | 5 | [signing] 6 | type = "file-based-signer" 7 | key-file = "/path/to/k2.key" 8 | password-file = "/path/to/p2.password" 9 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/duplicate_bar_627306090abab3a6e1400e9345bc60c78a8bef61.toml: -------------------------------------------------------------------------------- 1 | [metadata] 2 | createdAt = 1994-11-05T08:15:30-05:00 3 | description = "Example of File based configuration" 4 | 5 | [signing] 6 | type = "file-based-signer" 7 | key-file = "/path/to/k2.key" 8 | password-file = "/path/to/p2.password" 9 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/duplicate_foo_627306090abab3a6e1400e9345bc60c78a8bef61.toml: -------------------------------------------------------------------------------- 1 | [metadata] 2 | createdAt = 1994-11-05T08:15:30-05:00 3 | description = "Example of File based configuration" 4 | 5 | [signing] 6 | type = "file-based-signer" 7 | key-file = "/path/to/k.key" 8 | password-file = "/path/to/p.password" 9 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/k.key: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"2fe66c68-f643-4a8a-9672-427d0456e1ba","address":"4897b54979b9bf339f13dd461628476430cf0ea5","crypto":{"ciphertext":"6488cd65ea6654c1a5083e8d93e63144250f5616785c8960eed71f76de52a6d7","cipherparams":{"iv":"ae0c07bea178acfdd31f10cb34efb18a"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"10d0fd16d66de3351bed29b6cb3839f18beafeaabe8831bb456e7b421c4187d9","n":8192,"r":8,"p":1},"mac":"4326717f0225b3e05fe0b97fe0f0882a542042c212e5ed99297de112d7a923d0"}} 2 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/key_password_relative_path.toml: -------------------------------------------------------------------------------- 1 | [metadata] 2 | createdAt = 1994-11-05T08:15:30-05:00 3 | description = "Example of File based configuration" 4 | 5 | [signing] 6 | type = "file-based-signer" 7 | key-file = "./path/to/k.key" 8 | password-file = "./path/to/p.password" 9 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/missing_key_and_password_file_fe3b557e8fb62b89f4916b721be55ceb828dbd78.toml: -------------------------------------------------------------------------------- 1 | [metadata] 2 | createdAt = 1994-11-05T08:15:30-05:00 3 | description = "Example of File based configuration" 4 | 5 | [signing] 6 | type = "file-based-signer" -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/missing_key_file_fe3b557e8fb62b89f4916b721be55ceb828dbd76.toml: -------------------------------------------------------------------------------- 1 | [metadata] 2 | createdAt = 1994-11-05T08:15:30-05:00 3 | description = "Example of File based configuration" 4 | 5 | [signing] 6 | type = "file-based-signer" 7 | password-file = "/path/to/p2.password" 8 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/missing_password_file_fe3b557e8fb62b89f4916b721be55ceb828dbd77.toml: -------------------------------------------------------------------------------- 1 | [metadata] 2 | createdAt = 1994-11-05T08:15:30-05:00 3 | description = "Example of File based configuration" 4 | 5 | [signing] 6 | type = "file-based-signer" 7 | key-file = "/path/to/k2.key" -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/p.password: -------------------------------------------------------------------------------- 1 | pantheon -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/test/resources/metadata-toml-configs/unknown_type_signer_fe3b557e8fb62b89f4916b721be55ceb828dbd75.toml: -------------------------------------------------------------------------------- 1 | [metadata] 2 | createdAt = 1994-11-05T08:15:30-05:00 3 | description = "Example of File based configuration" 4 | 5 | [signing] 6 | type = "unknown-type-signer" 7 | key-file = "/path/to/k2.key" 8 | password-file = "/path/to/p2.password" 9 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/testFixtures/java/tech/pegasys/signers/secp256k1/common/PublicKeySignerIdentifier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.common; 14 | 15 | import static tech.pegasys.signers.secp256k1.api.util.AddressUtil.remove0xPrefix; 16 | 17 | import tech.pegasys.signers.secp256k1.EthPublicKeyUtils; 18 | import tech.pegasys.signers.secp256k1.api.SignerIdentifier; 19 | 20 | import java.security.interfaces.ECPublicKey; 21 | 22 | public class PublicKeySignerIdentifier implements SignerIdentifier { 23 | private final ECPublicKey publicKey; 24 | 25 | public PublicKeySignerIdentifier(final ECPublicKey publicKey) { 26 | this.publicKey = publicKey; 27 | } 28 | 29 | @Override 30 | public String toStringIdentifier() { 31 | return remove0xPrefix(EthPublicKeyUtils.toHexString(publicKey)); 32 | } 33 | 34 | @Override 35 | public boolean validate(final ECPublicKey publicKey) { 36 | return EthPublicKeyUtils.toHexString(this.publicKey) 37 | .equalsIgnoreCase(EthPublicKeyUtils.toHexString(publicKey)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /signing/secp256k1/impl/src/testFixtures/java/tech/pegasys/signers/secp256k1/common/TomlStringBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ConsenSys AG. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package tech.pegasys.signers.secp256k1.common; 14 | 15 | /** Create toml String with header. Note: To be used in tests only. */ 16 | public class TomlStringBuilder { 17 | private final StringBuilder stringBuilder = new StringBuilder(); 18 | 19 | public TomlStringBuilder(final String header) { 20 | stringBuilder.append(String.format("[%s]\n", header)); 21 | } 22 | 23 | public TomlStringBuilder withQuotedString(final String key, final String value) { 24 | stringBuilder.append(String.format("%s=\"%s\"\n", key, value)); 25 | return this; 26 | } 27 | 28 | public TomlStringBuilder withNonQuotedString(final String key, final String value) { 29 | stringBuilder.append(String.format("%s=%s\n", key, value)); 30 | return this; 31 | } 32 | 33 | public String build() { 34 | return stringBuilder.toString(); 35 | } 36 | } 37 | --------------------------------------------------------------------------------