diff --git a/docs/source/hsm-crl-generator.rst b/docs/source/hsm-crl-generator.rst new file mode 100644 index 0000000000..19cc5e8be9 --- /dev/null +++ b/docs/source/hsm-crl-generator.rst @@ -0,0 +1,18 @@ +HSM Certificate Generation Tool +=============================== + +The purpose of the HSM Certificate Revocation List (CRL) Generation Tool is to provide means for the ROOT signed CRL creation. +Currently, only the NODE-level CRL creation is automated. Other levels (i.e. INTERMEDIATE and TLS) need to be addressed as well. +Since we do not presume to update the INTERMEDIATE-level CRL often, the automation in this case is not required. +With respect to the TLS certificates, we (from the perspective of R3) are not the maintainers of those CRLs. +It is a customer responsibility to maintain those lists. However, in order to ensure correct CRL checking procedure in case of the +SSL communication we need to provide the endpoint serving an empty CRL in case the customer is not able to provide for a CRL infrastructure. +Thus necessity for an empty CRL creation. + +The HSM CRL Generation Tool allows for both empty and non-empty CRL creation. It can be configured to generate direct and indirect CRLs. +A direct CRL is a CRL issued by the certificate issuer, which applies to the INTERMEDIATE certificates. +However, sometimes there is a need for creating an indirect CRL - i.e. issued by another authority different than the certificate issuer. This is the case in the TLS certificates. +The tool is implemented in such a way that the ROOT CA is always the issuing authority. Depending on the configuration, the generated +CRL can be flagged as direct or indirect. + +The output of the tool is a file containing ASN.1 DER-encoded bytes of the generated CRL. \ No newline at end of file diff --git a/docs/source/running-hsm-cert-generator.rst b/docs/source/running-hsm-cert-generator.rst index 329f9cd235..66d320303d 100644 --- a/docs/source/running-hsm-cert-generator.rst +++ b/docs/source/running-hsm-cert-generator.rst @@ -13,7 +13,7 @@ Configuration file At startup, the HSM Certificate Generation Tool reads a configuration file, passed with ``--config-file`` on the command line. This is an example of what a tool configuration file might look like: - .. literalinclude:: ../../network-management/generator.conf + .. literalinclude:: ../../network-management/cert-generator.conf General configuration parameters -------------------------------- @@ -61,9 +61,9 @@ Certificate Configuration :keyOverride: Whether to override the key if already exists or not. 1 for override and 0 for NOT override. -:keySpecifier: This is an HSM specific parameter that corresponds to key name spacing. See Utimaco documentation for more details. +:keySpecifier: This is an HSM specific parameter that corresponds to key name spacing of the generated key. See Utimaco documentation for more details. -:keyGroup: This is an HSM specific parameter that corresponds to key name spacing for the generated key. See Utimaco documentation for more details. +:keyGroup: This is an HSM specific parameter that corresponds to key name grouping of the generated key. See Utimaco documentation for more details. User Authentication Configuration @@ -72,7 +72,7 @@ Allowed parameters are: :username: HSM username. This user needs to be allowed to generate keys/certificates and store them in HSM. -:authMode: One of the 2 possible authentication modes: +:authMode: One of the 3 possible authentication modes: PASSWORD - User's password as set-up in the HSM CARD_READER - Smart card reader authentication KEY_FILE - Key file based authentication. diff --git a/docs/source/running-hsm-crl-generator.rst b/docs/source/running-hsm-crl-generator.rst new file mode 100644 index 0000000000..e09f3a505b --- /dev/null +++ b/docs/source/running-hsm-crl-generator.rst @@ -0,0 +1,76 @@ +Running the HSM Certificate Generation tool +=========================================== + +The purpose of this tool is to facilitate the process of CRL generation using the ROOT certificate stored on the HSM infrastructure. +See :doc:`hsm-crl-generator` for more details. + + +See the Readme under ``network-management`` for detailed building instructions. + + +Configuration file +------------------ +At startup, the HSM CRL Generation Tool reads a configuration file, passed with ``--config-file`` on the command line. + +This is an example of what a tool configuration file might look like: + .. literalinclude:: ../../network-management/crl-generator.conf + +General configuration parameters +-------------------------------- +Allowed parameters are: + +:hsmHost: IP address of the HSM device. + +:hsmPort: Port number of the HSM device. + +:userConfigs: List of user authentication configurations. See below section on User Authentication Configuration. + +:crl: CRL specific configuration. See below section on CRL Configuration. + +:trustStoreFile: Path to the trust store file containing the ROOT certificate. + +:trustStorePassword: Password for the trust store. + + +CRL Configuration +----------------- + +:keySpecifier: This is an HSM specific parameter that corresponds to ROOT key name spacing. See Utimaco documentation for more details. + +:keyGroup: This is an HSM specific parameter that corresponds to ROOT key name grouping. See Utimaco documentation for more details. + +:validDays: Validity period of this CRL expressed in days. + +:crlEndpoint: URL pointing to the endpoint where this CRL can be obtained from. It is embedded in the generated CRL. + +:indirectIssuer: A boolean flag noting whether this CRL was issued by the certificate issuer (false) or another issuer (true). + +:filePath: Path to the generated file. + +:revocations: A list of revoked certificate data that is to be included in the generated CRL. Default value is the empty list. + See below for more details on the revoked certificate data. + +Revoked Certificate Data +------------------------ + +:certificateSerialNumber: Serial number of the revoked certificate. + +:dateInMillis: Certificate revocation time. + +:reason: Reason for the certificate revocation. The allowed value is one of the following: + UNSPECIFIED, KEY_COMPROMISE, CA_COMPROMISE, AFFILIATION_CHANGED, SUPERSEDED, CESSATION_OF_OPERATION, PRIVILEGE_WITHDRAWN + +User Authentication Configuration +--------------------------------- +Allowed parameters are: + +:username: HSM username. This user needs to be allowed to generate keys/certificates and store them in HSM. + +:authMode: One of the 3 possible authentication modes: + PASSWORD - User's password as set-up in the HSM + CARD_READER - Smart card reader authentication + KEY_FILE - Key file based authentication. + +:authToken: Depending on the authMode it is either user's password or path to the authentication key file. In case of the CARD_READER authMode value, this can be omitted. + +:keyFilePassword: Only relevant, if authMode == KEY_FILE. It is the key file password. \ No newline at end of file diff --git a/network-management/README.md b/network-management/README.md index 353a8fcd15..dade095078 100644 --- a/network-management/README.md +++ b/network-management/README.md @@ -48,6 +48,18 @@ The built file will appear in network-management/capsule-hsm-cert-generator/build/libs/hsm-cert-generator-.jar ``` +## HSM CRL Generator + +To build a fat jar containing all the hsm CRL generator code you can simply invoke +``` + ./gradlew network-management:capsule-hsm-crl-generator:buildHsmCrlGeneratorJAR +``` + +The built file will appear in +``` +network-management/capsule-hsm-crl-generator/build/libs/hsm-crl-generator-.jar +``` + ## Certificate Revocation Request Submission Tool To build a fat jar containing all the CRR submission tool code you can simply invoke diff --git a/network-management/capsule-hsm-cert-generator/build.gradle b/network-management/capsule-hsm-cert-generator/build.gradle index b09341b774..8f62714baa 100644 --- a/network-management/capsule-hsm-cert-generator/build.gradle +++ b/network-management/capsule-hsm-cert-generator/build.gradle @@ -20,7 +20,7 @@ configurations { } task buildHsmCertGeneratorJAR(type: FatCapsule, dependsOn: 'jar') { - applicationClass 'com.r3.corda.networkmanage.hsm.generator.MainKt' + applicationClass 'com.r3.corda.networkmanage.hsm.generator.certificate.MainKt' archiveName "hsm-cert-generator-${version}.jar" capsuleManifest { applicationVersion = corda_release_version diff --git a/network-management/capsule-hsm-crl-generator/build.gradle b/network-management/capsule-hsm-crl-generator/build.gradle new file mode 100644 index 0000000000..1d62be19fc --- /dev/null +++ b/network-management/capsule-hsm-crl-generator/build.gradle @@ -0,0 +1,49 @@ +/* + * R3 Proprietary and Confidential + * + * Copyright (c) 2018 R3 Limited. All rights reserved. + * + * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. + * + * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. + */ + +apply plugin: 'net.corda.plugins.publish-utils' +apply plugin: 'us.kirchmeier.capsule' + +description 'HSM Certificate Generator' + +version project(':network-management').version + +configurations { + runtimeArtifacts.extendsFrom runtime +} + +task buildHsmCrlGeneratorJAR(type: FatCapsule, dependsOn: 'jar') { + applicationClass 'com.r3.corda.networkmanage.hsm.generator.crl.MainKt' + archiveName "hsm-crl-generator-${version}.jar" + capsuleManifest { + applicationVersion = corda_release_version + systemProperties['visualvm.display.name'] = 'HSM CRL Generator' + minJavaVersion = '1.8.0' + jvmArgs = ['-XX:+UseG1GC'] + } + applicationSource = files( + project(':network-management').configurations.runtime, + project(':network-management').jar + ) +} + +artifacts { + runtimeArtifacts buildHsmCrlGeneratorJAR + publish buildHsmCrlGeneratorJAR +} + +jar { + classifier "ignore" +} + +publish { + name 'hsm-crl-generator' + disableDefaultJar = true +} \ No newline at end of file diff --git a/network-management/generator.conf b/network-management/cert-generator.conf similarity index 100% rename from network-management/generator.conf rename to network-management/cert-generator.conf diff --git a/network-management/crl-generator.conf b/network-management/crl-generator.conf new file mode 100644 index 0000000000..b6e51b144e --- /dev/null +++ b/network-management/crl-generator.conf @@ -0,0 +1,33 @@ +hsmHost = 127.0.0.1 +hsmPort = 3001 +trustStoreFile = "./truststore.jks" +trustStorePassword = "trustpass" + +crl { + keyGroup = "TEST.CORDACONNECT.ROOT" + keySpecifier = 1 + validDays = 3650 + crlEndpoint = "http://test.com/crl" + indirectIssuer = true + filePath = "./bytes.crl" + revocations = [ + { + certificateSerialNumber = "12345" + dateInMillis = 1526643707290 + reason = "KEY_COMPROMISE" + }, + { + certificateSerialNumber = "6789012" + dateInMillis = 1526643712345 + reason = "KEY_COMPROMISE" + } + ] +} + +userConfigs = [ + { + username = "INTEGRATION_TEST" + authMode = PASSWORD + authToken = "INTEGRATION_TEST" + } +] diff --git a/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/common/HsmBaseTest.kt b/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/common/HsmBaseTest.kt index 623be2f799..62211f8fad 100644 --- a/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/common/HsmBaseTest.kt +++ b/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/common/HsmBaseTest.kt @@ -14,11 +14,12 @@ import com.nhaarman.mockito_kotlin.any import com.nhaarman.mockito_kotlin.mock import com.nhaarman.mockito_kotlin.whenever import com.r3.corda.networkmanage.HsmSimulator +import com.r3.corda.networkmanage.hsm.authentication.CryptoServerProviderConfig import com.r3.corda.networkmanage.hsm.authentication.InputReader import com.r3.corda.networkmanage.hsm.configuration.* -import com.r3.corda.networkmanage.hsm.generator.CertificateConfiguration -import com.r3.corda.networkmanage.hsm.generator.GeneratorParameters import com.r3.corda.networkmanage.hsm.generator.UserAuthenticationParameters +import com.r3.corda.networkmanage.hsm.generator.certificate.CertificateConfiguration +import com.r3.corda.networkmanage.hsm.generator.certificate.GeneratorParameters import net.corda.core.crypto.random63BitValue import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort @@ -43,9 +44,9 @@ abstract class HsmBaseTest : IntegrationTest() { const val ROOT_CERT_KEY_GROUP = "TEST.CORDACONNECT.ROOT" const val NETWORK_MAP_CERT_KEY_GROUP = "TEST.CORDACONNECT.OPS.NETMAP" const val DOORMAN_CERT_KEY_GROUP = "TEST.CORDACONNECT.OPS.CERT" - const val ROOT_CERT_SUBJECT = "CN=Corda Root CA, O=R3 Ltd, OU=Corda, L=London, C=GB" - const val NETWORK_MAP_CERT_SUBJECT = "CN=Corda Network Map, O=R3 Ltd, OU=Corda, L=London, C=GB" - const val DOORMAN_CERT_SUBJECT = "CN=Corda Doorman CA, O=R3 Ltd, OU=Corda, L=London, C=GB" + const val ROOT_CERT_SUBJECT = "CN=Corda Root CA, OU=Corda, O=R3 Ltd, L=London, C=GB" + const val NETWORK_MAP_CERT_SUBJECT = "CN=Corda Network Map, OU=Corda, O=R3 Ltd, L=London, C=GB" + const val DOORMAN_CERT_SUBJECT = "CN=Corda Doorman CA, OU=Corda, O=R3 Ltd, L=London, C=GB" const val TRUSTSTORE_PASSWORD: String = "trustpass" const val HSM_USERNAME = "INTEGRATION_TEST" const val HSM_PASSWORD = "INTEGRATION_TEST" @@ -191,4 +192,12 @@ abstract class HsmBaseTest : IntegrationTest() { fun makeTestDatabaseProperties(): DatabaseConfig { return makeTestDatabaseProperties(DOORMAN_DB_NAME, configSupplier = configSupplierForSupportedDatabases()) } + + protected fun createProviderConfig(keyGroup: String): CryptoServerProviderConfig { + return CryptoServerProviderConfig( + Device = "${hsmSimulator.port}@${hsmSimulator.host}", + KeySpecifier = 1, + KeyGroup = keyGroup, + StoreKeysExternal = false) + } } \ No newline at end of file diff --git a/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmEmptyCrlGenerationTest.kt b/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmEmptyCrlGenerationTest.kt new file mode 100644 index 0000000000..2159eb8c43 --- /dev/null +++ b/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmEmptyCrlGenerationTest.kt @@ -0,0 +1,137 @@ +/* + * R3 Proprietary and Confidential + * + * Copyright (c) 2018 R3 Limited. All rights reserved. + * + * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. + * + * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. + */ + +package com.r3.corda.networkmanage.hsm + +import com.nhaarman.mockito_kotlin.any +import com.nhaarman.mockito_kotlin.mock +import com.nhaarman.mockito_kotlin.whenever +import com.r3.corda.networkmanage.common.HsmBaseTest +import com.r3.corda.networkmanage.hsm.authentication.InputReader +import com.r3.corda.networkmanage.hsm.generator.AutoAuthenticator +import com.r3.corda.networkmanage.hsm.generator.UserAuthenticationParameters +import com.r3.corda.networkmanage.hsm.generator.crl.CrlConfig +import com.r3.corda.networkmanage.hsm.generator.crl.GeneratorConfig +import com.r3.corda.networkmanage.hsm.generator.crl.RevocationConfig +import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities +import net.corda.nodeapi.internal.crypto.CertificateType +import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA +import org.apache.commons.io.FileUtils +import org.junit.Before +import org.junit.Test +import java.net.URL +import java.security.cert.CertificateFactory +import java.security.cert.X509CRL +import java.security.cert.X509Certificate +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertTrue +import com.r3.corda.networkmanage.hsm.generator.certificate.run as runCertificateGeneration +import com.r3.corda.networkmanage.hsm.generator.crl.run as runCrlGeneration + +class HsmEmptyCrlGenerationTest : HsmBaseTest() { + + private lateinit var inputReader: InputReader + + @Before + override fun setUp() { + super.setUp() + inputReader = mock() + whenever(inputReader.readLine()).thenReturn(hsmSimulator.cryptoUserCredentials().username) + whenever(inputReader.readPassword(any())).thenReturn(hsmSimulator.cryptoUserCredentials().password) + } + + @Test + fun `An empty CRL is generated`() { + // when root cert is created + runCertificateGeneration(createGeneratorParameters( + keyGroup = ROOT_CERT_KEY_GROUP, + rootKeyGroup = null, + certificateType = CertificateType.ROOT_CA, + subject = ROOT_CERT_SUBJECT + )) + + // then root cert is persisted in the HSM + AutoAuthenticator(createProviderConfig(ROOT_CERT_KEY_GROUP), HSM_USER_CONFIGS).connectAndAuthenticate { provider -> + val keyStore = HsmX509Utilities.getAndInitializeKeyStore(provider) + val rootCert = keyStore.getCertificate(CORDA_ROOT_CA) as X509Certificate + assertEquals(rootCert.issuerX500Principal, rootCert.subjectX500Principal) + } + + val generatedFile = tempFolder.newFile() + runCrlGeneration(createCrlGeneratorParameters(CrlConfig( + crlEndpoint = URL("http://test.com/crl"), + filePath = generatedFile.toPath(), + keyGroup = ROOT_CERT_KEY_GROUP, + keySpecifier = 1, + validDays = 1000, + indirectIssuer = true, + revocations = emptyList()), HSM_ROOT_USER_CONFIGS)) + val crl = CertificateFactory.getInstance("X.509") + .generateCRL(FileUtils.readFileToByteArray(generatedFile).inputStream()) as X509CRL + assertNotNull(crl) + assertEquals(ROOT_CERT_SUBJECT, crl.issuerDN.name) + assertTrue { crl.revokedCertificates.isEmpty() } + } + + @Test + fun `A non-empty CRL is generated`() { + // when root cert is created + runCertificateGeneration(createGeneratorParameters( + keyGroup = ROOT_CERT_KEY_GROUP, + rootKeyGroup = null, + certificateType = CertificateType.ROOT_CA, + subject = ROOT_CERT_SUBJECT + )) + + // then root cert is persisted in the HSM + AutoAuthenticator(createProviderConfig(ROOT_CERT_KEY_GROUP), HSM_USER_CONFIGS).connectAndAuthenticate { provider -> + val keyStore = HsmX509Utilities.getAndInitializeKeyStore(provider) + val rootCert = keyStore.getCertificate(CORDA_ROOT_CA) as X509Certificate + assertEquals(rootCert.issuerX500Principal, rootCert.subjectX500Principal) + } + + val generatedFile = tempFolder.newFile() + val revokedSerialNumber = "1234567890" + runCrlGeneration(createCrlGeneratorParameters(CrlConfig( + crlEndpoint = URL("http://test.com/crl"), + filePath = generatedFile.toPath(), + keyGroup = ROOT_CERT_KEY_GROUP, + keySpecifier = 1, + validDays = 1000, + indirectIssuer = false, + revocations = listOf( + RevocationConfig( + certificateSerialNumber = "1234567890", + dateInMillis = 0, + reason = "KEY_COMPROMISE" + ) + )), HSM_ROOT_USER_CONFIGS)) + val crl = CertificateFactory.getInstance("X.509") + .generateCRL(FileUtils.readFileToByteArray(generatedFile).inputStream()) as X509CRL + assertNotNull(crl) + assertEquals(ROOT_CERT_SUBJECT, crl.issuerDN.name) + assertEquals(1, crl.revokedCertificates.size) + val revoked = crl.revokedCertificates.first() + assertEquals(revoked.serialNumber.toString(), revokedSerialNumber) + } + + private fun createCrlGeneratorParameters(crlConfg: CrlConfig, + userConfigs: List): GeneratorConfig { + return GeneratorConfig( + hsmHost = hsmSimulator.host, + hsmPort = hsmSimulator.port, + trustStoreFile = rootKeyStoreFile, + trustStorePassword = TRUSTSTORE_PASSWORD, + userConfigs = userConfigs, + crl = crlConfg + ) + } +} \ No newline at end of file diff --git a/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmKeyGenerationTest.kt b/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmKeyGenerationTest.kt index 1288301bef..b7144f9e80 100644 --- a/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmKeyGenerationTest.kt +++ b/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmKeyGenerationTest.kt @@ -15,10 +15,9 @@ import com.nhaarman.mockito_kotlin.mock import com.nhaarman.mockito_kotlin.whenever import com.r3.corda.networkmanage.common.HsmBaseTest import com.r3.corda.networkmanage.common.utils.CORDA_NETWORK_MAP -import com.r3.corda.networkmanage.hsm.authentication.CryptoServerProviderConfig import com.r3.corda.networkmanage.hsm.authentication.InputReader import com.r3.corda.networkmanage.hsm.generator.AutoAuthenticator -import com.r3.corda.networkmanage.hsm.generator.run +import com.r3.corda.networkmanage.hsm.generator.certificate.run import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities import net.corda.core.identity.CordaX500Name import net.corda.nodeapi.internal.crypto.CertificateType @@ -93,12 +92,4 @@ class HsmKeyGenerationTest : HsmBaseTest() { assertEquals(CordaX500Name.parse(ROOT_CERT_SUBJECT).x500Principal, networkMapCert.issuerX500Principal) } } - - private fun createProviderConfig(keyGroup: String): CryptoServerProviderConfig { - return CryptoServerProviderConfig( - Device = "${hsmSimulator.port}@${hsmSimulator.host}", - KeySpecifier = 1, - KeyGroup = keyGroup, - StoreKeysExternal = false) - } } \ No newline at end of file diff --git a/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmPermissionTest.kt b/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmPermissionTest.kt index 177650369d..523e5e4e26 100644 --- a/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmPermissionTest.kt +++ b/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmPermissionTest.kt @@ -15,7 +15,7 @@ import com.r3.corda.networkmanage.common.HsmBaseTest import com.r3.corda.networkmanage.hsm.authentication.Authenticator import com.r3.corda.networkmanage.hsm.authentication.createProvider import com.r3.corda.networkmanage.hsm.generator.UserAuthenticationParameters -import com.r3.corda.networkmanage.hsm.generator.run +import com.r3.corda.networkmanage.hsm.generator.certificate.run import com.r3.corda.networkmanage.hsm.persistence.ApprovedCertificateRequestData import com.r3.corda.networkmanage.hsm.signer.HsmCsrSigner import net.corda.core.crypto.Crypto.generateKeyPair @@ -149,25 +149,25 @@ class HsmPermissionTest : HsmBaseTest() { netMapCertUserConfigs: List) { // when root cert is created run(createGeneratorParameters( - keyGroup = HsmBaseTest.ROOT_CERT_KEY_GROUP, + keyGroup = ROOT_CERT_KEY_GROUP, rootKeyGroup = null, certificateType = CertificateType.ROOT_CA, - subject = HsmBaseTest.ROOT_CERT_SUBJECT, + subject = ROOT_CERT_SUBJECT, hsmUserConfigs = rootCertUserConfigs)) // when network map cert is created run(createGeneratorParameters( - keyGroup = HsmBaseTest.NETWORK_MAP_CERT_KEY_GROUP, - rootKeyGroup = HsmBaseTest.ROOT_CERT_KEY_GROUP, + keyGroup = NETWORK_MAP_CERT_KEY_GROUP, + rootKeyGroup = ROOT_CERT_KEY_GROUP, certificateType = CertificateType.NETWORK_MAP, - subject = HsmBaseTest.NETWORK_MAP_CERT_SUBJECT, + subject = NETWORK_MAP_CERT_SUBJECT, hsmUserConfigs = netMapCertUserConfigs )) // when doorman cert is created run(createGeneratorParameters( - keyGroup = HsmBaseTest.DOORMAN_CERT_KEY_GROUP, - rootKeyGroup = HsmBaseTest.ROOT_CERT_KEY_GROUP, + keyGroup = DOORMAN_CERT_KEY_GROUP, + rootKeyGroup = ROOT_CERT_KEY_GROUP, certificateType = CertificateType.INTERMEDIATE_CA, - subject = HsmBaseTest.DOORMAN_CERT_SUBJECT, + subject = DOORMAN_CERT_SUBJECT, hsmUserConfigs = doormanCertUserConfigs )) } diff --git a/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmSigningServiceTest.kt b/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmSigningServiceTest.kt index d66ed47000..77fe191a34 100644 --- a/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmSigningServiceTest.kt +++ b/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/hsm/HsmSigningServiceTest.kt @@ -19,7 +19,7 @@ import com.r3.corda.networkmanage.common.utils.CORDA_NETWORK_MAP import com.r3.corda.networkmanage.common.utils.initialiseSerialization import com.r3.corda.networkmanage.hsm.authentication.Authenticator import com.r3.corda.networkmanage.hsm.authentication.createProvider -import com.r3.corda.networkmanage.hsm.generator.run +import com.r3.corda.networkmanage.hsm.generator.certificate.run import com.r3.corda.networkmanage.hsm.persistence.ApprovedCertificateRequestData import com.r3.corda.networkmanage.hsm.signer.HsmCsrSigner import com.r3.corda.networkmanage.hsm.signer.HsmSigner diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/CertificateRevocationListSigner.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/CertificateRevocationListSigner.kt index 38f6754fd1..7f3a08300d 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/CertificateRevocationListSigner.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/CertificateRevocationListSigner.kt @@ -4,6 +4,7 @@ import com.r3.corda.networkmanage.common.persistence.CertificateRevocationListSt import com.r3.corda.networkmanage.common.persistence.CertificateRevocationRequestData import com.r3.corda.networkmanage.common.persistence.CrlIssuer import com.r3.corda.networkmanage.common.persistence.RequestStatus +import com.r3.corda.networkmanage.common.utils.Revocation import com.r3.corda.networkmanage.common.utils.createSignedCrl import net.corda.core.utilities.contextLogger import net.corda.core.utilities.debug @@ -13,6 +14,7 @@ import java.security.cert.X509CRL import java.security.cert.X509Certificate import java.time.Duration import java.time.Instant +import java.util.* class CertificateRevocationListSigner( private val revocationListStorage: CertificateRevocationListStorage, @@ -48,7 +50,10 @@ class CertificateRevocationListSigner( logger.trace { "Approved Certificate Revocation Requests to be included in the new Certificate Revocation List: $approvedWithTimestamp" } logger.debug("Retrieving revoked Certificate Revocation Requests...") logger.trace { "Revoked Certificate Revocation Requests to be included in the new Certificate Revocation List: $existingCRRs" } - val crl = createSignedCrl(issuerCertificate, endpoint, updateInterval, signer, existingCRRs + approvedWithTimestamp) + val revocations = (existingCRRs + approvedWithTimestamp).map { + Revocation(it.certificateSerialNumber, Date(it.modifiedAt.toEpochMilli()), it.reason) + } + val crl = createSignedCrl(issuerCertificate, endpoint, updateInterval, signer, revocations) logger.debug { "Created a new Certificate Revocation List $crl" } revocationListStorage.saveCertificateRevocationList(crl, CrlIssuer.DOORMAN, signedBy, revocationTime) logger.info("A new Certificate Revocation List has been persisted.") diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/CrlUtils.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/CrlUtils.kt index bf48596fc9..cbea01a593 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/CrlUtils.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/CrlUtils.kt @@ -1,6 +1,5 @@ package com.r3.corda.networkmanage.common.utils -import com.r3.corda.networkmanage.common.persistence.CertificateRevocationRequestData import com.r3.corda.networkmanage.common.signer.Signer import net.corda.nodeapi.internal.crypto.X509Utilities import org.bouncycastle.asn1.x500.X500Name @@ -12,7 +11,9 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider import org.bouncycastle.operator.ContentSigner import java.io.ByteArrayOutputStream import java.io.OutputStream +import java.math.BigInteger import java.net.URL +import java.security.cert.CRLReason import java.security.cert.X509CRL import java.security.cert.X509Certificate import java.time.Duration @@ -23,7 +24,7 @@ fun createSignedCrl(issuerCertificate: X509Certificate, endpointUrl: URL, nextUpdateInterval: Duration, signer: Signer, - includeInCrl: List, + includeInCrl: List, indirectIssuingPoint: Boolean = false): X509CRL { val extensionUtils = JcaX509ExtensionUtils() val builder = X509v2CRLBuilder(X500Name.getInstance(issuerCertificate.subjectX500Principal.encoded), Date()) @@ -33,12 +34,14 @@ fun createSignedCrl(issuerCertificate: X509Certificate, builder.addExtension(Extension.issuingDistributionPoint, true, issuingDistributionPoint) builder.setNextUpdate(Date(Instant.now().toEpochMilli() + nextUpdateInterval.toMillis())) includeInCrl.forEach { - builder.addCRLEntry(it.certificateSerialNumber, Date(it.modifiedAt.toEpochMilli()), it.reason.ordinal) + builder.addCRLEntry(it.certificateSerialNumber, it.date, it.reason.ordinal) } val crlHolder = builder.build(CrlContentSigner(signer)) return JcaX509CRLConverter().setProvider(BouncyCastleProvider()).getCRL(crlHolder) } +data class Revocation(val certificateSerialNumber: BigInteger, val date: Date, val reason: CRLReason) + private class CrlContentSigner(private val signer: Signer) : ContentSigner { private val outputStream = ByteArrayOutputStream() @@ -46,4 +49,14 @@ private class CrlContentSigner(private val signer: Signer) : ContentSigner { override fun getAlgorithmIdentifier(): AlgorithmIdentifier = X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME.signatureOID override fun getOutputStream(): OutputStream = outputStream override fun getSignature(): ByteArray = signer.signBytes(outputStream.toByteArray()).bytes +} + +enum class SupportedCrlReasons { + UNSPECIFIED, + KEY_COMPROMISE, + CA_COMPROMISE, + AFFILIATION_CHANGED, + SUPERSEDED, + CESSATION_OF_OPERATION, + PRIVILEGE_WITHDRAWN } \ No newline at end of file diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/AutoAuthenticator.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/AutoAuthenticator.kt index 99108c335e..707abc9c0e 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/AutoAuthenticator.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/AutoAuthenticator.kt @@ -14,6 +14,27 @@ import CryptoServerJCE.CryptoServerProvider import com.r3.corda.networkmanage.hsm.authentication.CryptoServerProviderConfig import com.r3.corda.networkmanage.hsm.authentication.createProvider +/** + * Holds configuration necessary for user's authentication against HSM. + */ +data class UserAuthenticationParameters(val username: String, + val authMode: AuthMode, + val authToken: String?, // password or path to the key file, depending on the [authMode] + val keyFilePassword: String?) { // used only if authMode == [AuthMode.KEY_FILE] + init { + require(keyFilePassword == null || authMode == AuthMode.KEY_FILE) { + "keyFilePassword can only be specified if the authMode is set to KEY_FILE" + } + } +} + +/** + * Supported authentication modes. + */ +enum class AuthMode { + PASSWORD, CARD_READER, KEY_FILE +} + /** * Performs user authentication against the HSM */ diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/GeneratorParameters.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/certificate/GeneratorParameters.kt similarity index 81% rename from network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/GeneratorParameters.kt rename to network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/certificate/GeneratorParameters.kt index d5c79f65cb..fd9fd5d7fc 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/GeneratorParameters.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/certificate/GeneratorParameters.kt @@ -8,8 +8,9 @@ * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. */ -package com.r3.corda.networkmanage.hsm.generator +package com.r3.corda.networkmanage.hsm.generator.certificate +import com.r3.corda.networkmanage.hsm.generator.UserAuthenticationParameters import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigParseOptions import net.corda.nodeapi.internal.config.UnknownConfigKeysPolicy @@ -17,21 +18,6 @@ import net.corda.nodeapi.internal.config.parseAs import net.corda.nodeapi.internal.crypto.CertificateType import java.nio.file.Path -/** - * Holds configuration necessary for user's authentication against HSM. - */ -data class UserAuthenticationParameters(val username: String, - val authMode: AuthMode, - val authToken: String?, // password or path to the key file, depending on the [authMode] - val keyFilePassword: String?) // used only if authMode == [AuthMode.KEY_FILE] - -/** - * Supported authentication modes. - */ -enum class AuthMode { - PASSWORD, CARD_READER, KEY_FILE -} - /** * Holds generator parameters. */ diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/KeyCertificateGenerator.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/certificate/KeyCertificateGenerator.kt similarity index 99% rename from network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/KeyCertificateGenerator.kt rename to network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/certificate/KeyCertificateGenerator.kt index f0e392ac8c..604e6ec8c1 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/KeyCertificateGenerator.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/certificate/KeyCertificateGenerator.kt @@ -8,7 +8,7 @@ * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. */ -package com.r3.corda.networkmanage.hsm.generator +package com.r3.corda.networkmanage.hsm.generator.certificate import CryptoServerCXI.CryptoServerCXI.KEY_ALGO_ECDSA import CryptoServerCXI.CryptoServerCXI.KeyAttributes diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/Main.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/certificate/Main.kt similarity index 93% rename from network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/Main.kt rename to network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/certificate/Main.kt index 81dcc6f158..7a5f35e5ad 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/Main.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/certificate/Main.kt @@ -8,15 +8,16 @@ * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. */ -package com.r3.corda.networkmanage.hsm.generator +package com.r3.corda.networkmanage.hsm.generator.certificate import com.r3.corda.networkmanage.common.configuration.ConfigFilePathArgsParser import com.r3.corda.networkmanage.hsm.authentication.CryptoServerProviderConfig +import com.r3.corda.networkmanage.hsm.generator.AutoAuthenticator import com.r3.corda.networkmanage.hsm.utils.mapCryptoServerException import net.corda.nodeapi.internal.crypto.CertificateType.ROOT_CA import org.apache.logging.log4j.LogManager -private val logger = LogManager.getLogger("com.r3.corda.networkmanage.hsm.generator.Main") +private val logger = LogManager.getLogger("com.r3.corda.networkmanage.hsm.generator.certificate.Main") fun main(args: Array) { run(parseParameters(ConfigFilePathArgsParser().parseOrExit(*args))) diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/crl/GeneratorConfig.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/crl/GeneratorConfig.kt new file mode 100644 index 0000000000..917e9f0a27 --- /dev/null +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/crl/GeneratorConfig.kt @@ -0,0 +1,81 @@ +/* + * R3 Proprietary and Confidential + * + * Copyright (c) 2018 R3 Limited. All rights reserved. + * + * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. + * + * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. + */ + +package com.r3.corda.networkmanage.hsm.generator.crl + +import com.r3.corda.networkmanage.common.utils.SupportedCrlReasons +import com.r3.corda.networkmanage.hsm.generator.UserAuthenticationParameters +import com.typesafe.config.ConfigFactory +import com.typesafe.config.ConfigParseOptions +import net.corda.nodeapi.internal.config.UnknownConfigKeysPolicy +import net.corda.nodeapi.internal.config.parseAs +import net.corda.nodeapi.internal.crypto.X509KeyStore +import java.net.URL +import java.nio.file.Path + +/** + * Holds generator parameters. + */ +data class GeneratorConfig(val hsmHost: String, + val hsmPort: Int, + val userConfigs: List, + val trustStoreFile: Path, + val trustStorePassword: String, + val crl: CrlConfig) { + fun loadTrustStore(): X509KeyStore { + return X509KeyStore.fromFile(trustStoreFile, trustStorePassword, false) + } +} + +/** + * Holds CRL specific configuration. + */ +data class CrlConfig(val keyGroup: String, + val keySpecifier: Int, + val validDays: Long, + val crlEndpoint: URL, + val indirectIssuer: Boolean, + val filePath: Path, + val revocations: List = emptyList()) + +/** + * Supported revocation reasons: + * UNSPECIFIED, + * KEY_COMPROMISE, + * CA_COMPROMISE, + * AFFILIATION_CHANGED, + * SUPERSEDED, + * CESSATION_OF_OPERATION, + * PRIVILEGE_WITHDRAWN + */ +data class RevocationConfig(val certificateSerialNumber: String, val dateInMillis: Long, val reason: String) { + + companion object { + val reasonErrorMessage = "Error when parsing the revocation reason. Allowed values: ${SupportedCrlReasons.values()}" + } + + init { + try { + SupportedCrlReasons.valueOf(reason) + } catch (e: Exception) { + throw IllegalArgumentException(reasonErrorMessage) + } + } +} + +/** + * Parses a configuration file, which contains all the configuration - i.e. for user and certificate parameters. + */ +fun parseParameters(configFile: Path): GeneratorConfig { + return ConfigFactory + .parseFile(configFile.toFile(), ConfigParseOptions.defaults().setAllowMissing(true)) + .resolve() + .parseAs(UnknownConfigKeysPolicy.IGNORE::handle) +} \ No newline at end of file diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/crl/Main.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/crl/Main.kt new file mode 100644 index 0000000000..0022fa129c --- /dev/null +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/crl/Main.kt @@ -0,0 +1,61 @@ +/* + * R3 Proprietary and Confidential + * + * Copyright (c) 2018 R3 Limited. All rights reserved. + * + * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. + * + * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. + */ + +package com.r3.corda.networkmanage.hsm.generator.crl + +import com.r3.corda.networkmanage.common.configuration.ConfigFilePathArgsParser +import com.r3.corda.networkmanage.common.utils.Revocation +import com.r3.corda.networkmanage.common.utils.createSignedCrl +import com.r3.corda.networkmanage.hsm.authentication.CryptoServerProviderConfig +import com.r3.corda.networkmanage.hsm.generator.AutoAuthenticator +import com.r3.corda.networkmanage.hsm.signer.HsmSigner +import com.r3.corda.networkmanage.hsm.utils.mapCryptoServerException +import net.corda.nodeapi.internal.crypto.X509Utilities +import org.apache.commons.io.FileUtils +import org.apache.logging.log4j.LogManager +import java.math.BigInteger +import java.security.cert.CRLReason +import java.time.Duration +import java.util.* + +private val logger = LogManager.getLogger("com.r3.corda.networkmanage.hsm.generator.crl.Main") + +fun main(args: Array) { + run(parseParameters(ConfigFilePathArgsParser().parseOrExit(*args))) +} + +fun run(parameters: GeneratorConfig) { + parameters.run { + val providerConfig = CryptoServerProviderConfig( + Device = "$hsmPort@$hsmHost", + KeySpecifier = crl.keySpecifier, + KeyGroup = crl.keyGroup) + try { + AutoAuthenticator(providerConfig, userConfigs).connectAndAuthenticate { provider -> + logger.info("Generating an empty CRL...") + val issuerCertificate = loadTrustStore().getCertificate(X509Utilities.CORDA_ROOT_CA) + val generatedCrl = createSignedCrl(issuerCertificate, + crl.crlEndpoint, + Duration.ofDays(crl.validDays), + HsmSigner(provider = provider, keyName = X509Utilities.CORDA_ROOT_CA), + crl.revocations.map { Revocation( + BigInteger(it.certificateSerialNumber), + Date(it.dateInMillis), + CRLReason.valueOf(it.reason) + ) }, + crl.indirectIssuer) + FileUtils.writeByteArrayToFile(crl.filePath.toFile(), generatedCrl.encoded) + provider.logoff() + } + } catch (e: Exception) { + logger.error("HSM CRL generation error.", mapCryptoServerException(e)) + } + } +} \ No newline at end of file diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/Main.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/Main.kt index 75beedbb5a..c11f7b9a0d 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/Main.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/Main.kt @@ -1,5 +1,6 @@ package com.r3.corda.networkmanage.tools.crr.submission +import com.r3.corda.networkmanage.common.utils.SupportedCrlReasons import com.r3.corda.networkmanage.common.utils.initialiseSerialization import com.r3.corda.networkmanage.hsm.authentication.ConsoleInputReader import com.r3.corda.networkmanage.hsm.authentication.InputReader @@ -55,16 +56,6 @@ private fun InputReader.getRequiredInput(attributeName: String): String { } } -private enum class SupportedCrlReasons { - UNSPECIFIED, - KEY_COMPROMISE, - CA_COMPROMISE, - AFFILIATION_CHANGED, - SUPERSEDED, - CESSATION_OF_OPERATION, - PRIVILEGE_WITHDRAWN -} - private fun getReason(inputReader: InputReader): CRLReason { while (true) { SupportedCrlReasons.values().forEachIndexed { index, value -> @@ -75,7 +66,7 @@ private fun getReason(inputReader: InputReader): CRLReason { if (input < 1 || input > SupportedCrlReasons.values().size) { println("Incorrect selection. Try again.") } else { - return CRLReason.valueOf(SupportedCrlReasons.values()[input -1 ].name) + return CRLReason.valueOf(SupportedCrlReasons.values()[input - 1].name) } } } \ No newline at end of file diff --git a/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/generator/GeneratorParametersTest.kt b/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/generator/cert/GeneratorParametersTest.kt similarity index 87% rename from network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/generator/GeneratorParametersTest.kt rename to network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/generator/cert/GeneratorParametersTest.kt index 82cbc84e7b..31b0396a16 100644 --- a/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/generator/GeneratorParametersTest.kt +++ b/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/generator/cert/GeneratorParametersTest.kt @@ -8,9 +8,12 @@ * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. */ -package com.r3.corda.networkmanage.hsm.generator +package com.r3.corda.networkmanage.hsm.generator.cert import com.r3.corda.networkmanage.common.configuration.ConfigFilePathArgsParser +import com.r3.corda.networkmanage.hsm.generator.AuthMode +import com.r3.corda.networkmanage.hsm.generator.certificate.GeneratorParameters +import com.r3.corda.networkmanage.hsm.generator.certificate.parseParameters import com.typesafe.config.ConfigException import joptsimple.OptionException import net.corda.nodeapi.internal.crypto.CertificateType @@ -23,8 +26,8 @@ import kotlin.test.assertFailsWith import kotlin.test.assertFalse class GeneratorParametersTest { - private val validConfigPath = File("generator.conf").absolutePath - private val invalidConfigPath = File(javaClass.getResource("/generator_fail.conf").toURI()).absolutePath + private val validConfigPath = File("cert-generator.conf").absolutePath + private val invalidConfigPath = File(javaClass.getResource("/cert-generator_fail.conf").toURI()).absolutePath private val validArgs = arrayOf("--config-file", validConfigPath) @Test diff --git a/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/generator/crl/GeneratorParametersTest.kt b/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/generator/crl/GeneratorParametersTest.kt new file mode 100644 index 0000000000..d428dfaecc --- /dev/null +++ b/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/generator/crl/GeneratorParametersTest.kt @@ -0,0 +1,67 @@ +/* + * R3 Proprietary and Confidential + * + * Copyright (c) 2018 R3 Limited. All rights reserved. + * + * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. + * + * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. + */ + +package com.r3.corda.networkmanage.hsm.generator.crl + +import com.r3.corda.networkmanage.common.configuration.ConfigFilePathArgsParser +import com.r3.corda.networkmanage.hsm.generator.AuthMode +import com.typesafe.config.ConfigException +import joptsimple.OptionException +import org.assertj.core.api.Assertions +import org.junit.Test +import java.io.File +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse + +class GeneratorParametersTest { + private val validConfigPath = File("crl-generator.conf").absolutePath + private val invalidConfigPath = File(javaClass.getResource("/crl-generator_fail.conf").toURI()).absolutePath + private val validArgs = arrayOf("--config-file", validConfigPath) + + @Test + fun `should fail when config file is missing`() { + val message = assertFailsWith { + ConfigFilePathArgsParser().parseOrExit("--config-file", "not-existing-file", printHelpOn = null) + }.message + Assertions.assertThat(message).contains("not-existing-file") + } + + @Test + fun `should fail when config is invalid`() { + assertFailsWith { + parseParameters(ConfigFilePathArgsParser().parseOrExit("--config-file", invalidConfigPath)) + } + } + + @Test + fun `should parse generator config correctly`() { + val parameters = parseCommandLineAndGetParameters() + assertEquals("127.0.0.1", parameters.hsmHost) + assertEquals(3001, parameters.hsmPort) + assertEquals("trustpass", parameters.trustStorePassword) + val crlConfig = parameters.crl + assertEquals(1, crlConfig.keySpecifier) + assertFalse(parameters.userConfigs.isEmpty()) + val revocationsConfig = crlConfig.revocations + assertEquals(2, revocationsConfig.size) + val revocationConfig = revocationsConfig.first() + assertEquals(revocationConfig.reason, "KEY_COMPROMISE") + assertEquals(revocationConfig.certificateSerialNumber, "12345") + val userConfig = parameters.userConfigs.first() + assertEquals("INTEGRATION_TEST", userConfig.username) + assertEquals(AuthMode.PASSWORD, userConfig.authMode) + assertEquals("INTEGRATION_TEST", userConfig.authToken) + } + + private fun parseCommandLineAndGetParameters(): GeneratorConfig { + return parseParameters(ConfigFilePathArgsParser().parseOrExit(*validArgs)) + } +} \ No newline at end of file diff --git a/network-management/src/test/resources/generator_fail.conf b/network-management/src/test/resources/cert-generator_fail.conf similarity index 100% rename from network-management/src/test/resources/generator_fail.conf rename to network-management/src/test/resources/cert-generator_fail.conf diff --git a/network-management/src/test/resources/crl-generator_fail.conf b/network-management/src/test/resources/crl-generator_fail.conf new file mode 100644 index 0000000000..e611a6cdad --- /dev/null +++ b/network-management/src/test/resources/crl-generator_fail.conf @@ -0,0 +1,12 @@ +hsmHost = 127.0.0.1 +hsmPort = 3001 +trustStoreFile = "./truststore.jks" +trustStorePassword = "trustpass" + +userConfigs = [ + { + username = "INTEGRATION_TEST" + authMode = PASSWORD + authToken = "INTEGRATION_TEST" + } +] \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index bc706e0813..6ebce63542 100644 --- a/settings.gradle +++ b/settings.gradle @@ -51,6 +51,7 @@ include 'network-management' include 'network-management:capsule' include 'network-management:capsule-hsm' include 'network-management:capsule-hsm-cert-generator' +include 'network-management:capsule-hsm-crl-generator' include 'network-management:capsule-crr-submission' include 'network-management:registration-tool' include 'tools:jmeter'