mirror of
https://github.com/corda/corda.git
synced 2025-03-14 08:16:32 +00:00
ENT-1883 Adding the CRL generator (#857)
* Adding the empty CRL generation functionality * Addressing review comments
This commit is contained in:
parent
c4f9f1cb68
commit
d9510d9a22
18
docs/source/hsm-crl-generator.rst
Normal file
18
docs/source/hsm-crl-generator.rst
Normal file
@ -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.
|
@ -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.
|
||||
|
76
docs/source/running-hsm-crl-generator.rst
Normal file
76
docs/source/running-hsm-crl-generator.rst
Normal file
@ -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.
|
@ -48,6 +48,18 @@ The built file will appear in
|
||||
network-management/capsule-hsm-cert-generator/build/libs/hsm-cert-generator-<VERSION>.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-<VERSION>.jar
|
||||
```
|
||||
|
||||
## Certificate Revocation Request Submission Tool
|
||||
|
||||
To build a fat jar containing all the CRR submission tool code you can simply invoke
|
||||
|
@ -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
|
||||
|
49
network-management/capsule-hsm-crl-generator/build.gradle
Normal file
49
network-management/capsule-hsm-crl-generator/build.gradle
Normal file
@ -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
|
||||
}
|
33
network-management/crl-generator.conf
Normal file
33
network-management/crl-generator.conf
Normal file
@ -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"
|
||||
}
|
||||
]
|
@ -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)
|
||||
}
|
||||
}
|
@ -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<UserAuthenticationParameters>): GeneratorConfig {
|
||||
return GeneratorConfig(
|
||||
hsmHost = hsmSimulator.host,
|
||||
hsmPort = hsmSimulator.port,
|
||||
trustStoreFile = rootKeyStoreFile,
|
||||
trustStorePassword = TRUSTSTORE_PASSWORD,
|
||||
userConfigs = userConfigs,
|
||||
crl = crlConfg
|
||||
)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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<UserAuthenticationParameters>) {
|
||||
// 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
|
||||
))
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.")
|
||||
|
@ -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<CertificateRevocationRequestData>,
|
||||
includeInCrl: List<Revocation>,
|
||||
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
|
||||
}
|
@ -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
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
@ -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
|
@ -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<String>) {
|
||||
run(parseParameters(ConfigFilePathArgsParser().parseOrExit(*args)))
|
@ -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<UserAuthenticationParameters>,
|
||||
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<RevocationConfig> = 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)
|
||||
}
|
@ -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<String>) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
@ -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<OptionException> {
|
||||
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<ConfigException.Missing> {
|
||||
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))
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
]
|
@ -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'
|
||||
|
Loading…
x
Reference in New Issue
Block a user