Implementing dual execution mode of the HSM signing service (#380)

* Implementing dual execution mode for the hsm signing service

* mend

* Addressing review comments

* Extracting processor classes
This commit is contained in:
Michal Kit 2018-02-08 16:54:07 +00:00 committed by GitHub
parent 8c5f0ac0ca
commit e6e2836119
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 468 additions and 321 deletions

View File

@ -33,13 +33,17 @@ Allowed parameters are:
:mode: must be one of: DOORMAN (default), CA_KEYGEN, ROOT_KEYGEN.
:approveAll: Whether to approve all request (defaults to false), this is for debug only.
:database: database properties. The same (including its default value) as for node configuration (see :doc:`corda-configuration-file`).
:dataSourceProperties: datasource properties
:jiraConfig: The Jira configuration
:doorman: Doorman specific configuration
:approveAll: Whether to approve all request (defaults to false), this is for debug only.
:approveInterval: How often to process Jira approved requests in seconds.
:jira: The Jira configuration
:address: The URL to use to connect to Jira
@ -49,7 +53,12 @@ Allowed parameters are:
:password: Password for Jira
:doneTransitionCode: Jira status to put approved tickets in
:networkMap: Network map specific configuration
:cacheTimeout: Network map cache entry expiry time (in milliseconds)
:signInterval: How often to sign the network map in seconds
:keystorePath: Path for the keystore. If not set (or null is passed) doorman will NOT perform any signing.
This is required in case of the HSM integration where signing process is offloaded (from doorman) to an external service
@ -57,10 +66,6 @@ Allowed parameters are:
:rootStorePath: Path for the root keystore
:approveInterval: How often to process Jira approved requests in seconds. This will also be added to the http header, to be use as poll interval in Corda client.
:signInterval: How often to sign the network map in seconds
Bootstrapping the network parameters
------------------------------------
When doorman is running it will serve the current network parameters. The first time doorman is

View File

@ -4,10 +4,10 @@ Running the signing service
The signing service is a bridge between the networking service and the HSM infrastructure. It is responsible for retrieving
pending requests for signatures and managing the process of securing these signatures from an HSM infrastructure.
The signing service has a console-based user interface (designed for the manual signing process of the certificate signing requests),
which upon successful startup should display different options to the user.
At the same time, it connects to the database (which is expected to be shared with Doorman)
and periodically polls it and if needed automatically signs the following: network map and certificate revocation list.
The signing service has two execution modes. Each mode focuses on signing one of the two different types of data: certificate signing requests and network map.
Signing of the network map is an automatic process (i.e. does not require human intervention) that retrieves from the database the network map data to be signed.
Certificate signing requests, on the other hand, require human-in-the-loop to be processed and therefore the signing process relies on the console-based interface, that allows for user interaction.
Depending on the configuration each of those processes can be enabled or disabled (see below for more details).
See the :doc:`signing-service` for a more detailed description of the service.
@ -28,52 +28,51 @@ Allowed parameters are:
:device: HSM connection string. It is of the following format 3001@127.0.0.1, where 3001 is the port number.
Default value: "3001@127.0.0.1"
:keySpecifier: HSM key specifier. This parameter is vendor specific (see Utimaco docs).
:database: Database properties.
:dataSourceProperties: Data source properties. It should describe (or point to) the Doorman database.
:csrSigning: CSR signing process configuration parameters. If specified, the signing service will sign approved CSRs.
:validDays: Number of days issued signatures are valid for.
:rootKeyStoreFile: Location of the key store (trust store) containing the root certificate.
:rootKeyStorePassword: Password for the key store (trust store) containing the root certificate.
:networkMapKeyGroup: HSM key group for the network map certificate key. This parameter is vendor specific (see Utimaco docs).
:keyGroup: HSM key group for the doorman certificate key. This parameter is vendor specific (see Utimaco docs).
:doormanKeyGroup: HSM key group for the doorman certificate key. This parameter is vendor specific (see Utimaco docs).
:crlDistributionPoint: Certificate revocation list location for the node CA certificate.
:keySpecifier: HSM key specifier. This parameter is vendor specific (see Utimaco docs). Default value: 1.
:authParameters: Authentication configuration for the CSR signing process.
:rootPrivateKeyPassword: Private key password for the root certificate.
:mode: Authentication mode. Allowed values are: PASSWORD, CARD_READER and KEY_FILE
:csrPrivateKeyPassword: Private key password for the intermediate certificate used to sign certficate signing requests.
:password: Key file password. Valid only if the authentication mode is set to KEY_FILE.
:csrCertCrlDistPoint: Certificate revocation list location for the node CA certificate.
:keyFilePath: Key file path. Valid only if authentication mode is set to KEY_FILE.
:csrCertCrlIssuer: Certificate revocation list issuer. The expected value is of the X500 name format - e.g. "L=London, C=GB, OU=Org Unit, CN=Service Name".
If not specified, the node CA certificate issuer is considered also as the CRL issuer.
:threshold: Minimum authentication strength threshold required for certificate signing requests.
:databaseProperties: Database properties.
:networkMapSigning: Network map signing process configuration parameters. If specified, the signing service will sign the network map.
:dataSourceProperties: Data source properties. It should describe (or point to) the Doorman database.
:username: HSM username to be used when communicating with the HSM.
:networkMapPrivateKeyPassword: Private key password for the intermediate certificate used to sign the network map.
:keyGroup: HSM key group for the network map certificate key. This parameter is vendor specific (see Utimaco docs).
:validDays: Number of days issued signatures are valid for.
:authParameters: Authentication configuration for the CSR signing process.
:signAuthThreshold: Minimum authentication strength threshold required for certificate signing requests.
Default value: 2
:mode: Authentication mode. Allowed values are: PASSWORD and KEY_FILE
:keyGenAuthThreshold: Minimum authentication strength threshold required for key generation.
Default value: 2
:password: If the authentication mode is set to KEY_FILE, then it is the key file password.
If the authentication mode is set to PASSWORD, then it is the password string.
:authMode: Authentication mode, used when validating a user for certificate signing request signature.
Allowed values are:
"PASSWORD" (default) - type-in password authentication
CARD_READER - smart card reader authentication
KEY_FILE - key file authentication
:keyFilePath: Key file path. Valid only if authentication mode is set to KEY_FILE.
:authKeyFilePath: Authentication key file. It is used when the 'authMode' is set to "KEY_FILE"
or for the automated signing process - e.g. network map, certificate revocation list. Default value: null
:threshold: Minimum authentication strength threshold required for certificate signing requests.
:authKeyFilePassword: Authentication key file password. It is used when the 'authMode' is set to "KEY_FILE"
or for the automated signing process - e.g. network map, certificate revocation list. Default value: null
:signInterval: Interval (in milliseconds) in which all automated signing happens. Default value: 60000 milliseconds
Expected behaviour and output upon the service start-up
-------------------------------------------------------

View File

@ -106,28 +106,29 @@ The doorman service can use JIRA to manage the certificate signing request appro
basedir = "."
host = localhost
port = 0
#For local signing
rootStorePath = ${basedir}"/certificates/rootstore.jks"
keystorePath = ${basedir}"/certificates/caKeystore.jks"
keystorePassword = "password"
caPrivateKeyPassword = "password"
# Database config
dataSourceProperties {
dataSourceClassName = org.h2.jdbcx.JdbcDataSource
"dataSource.url" = "jdbc:h2:file:"${basedir}"/persistence;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;WRITE_DELAY=0;AUTO_SERVER_PORT="${h2port}
"dataSource.user" = sa
"dataSource.password" = ""
}
database {
runMigration = true
}
h2port = 0
# Doorman config
# Comment out this section if running without doorman service
doormanConfig {
doorman {
approveInterval = 10000
approveAll = false
jiraConfig {
jira {
address = "https://doorman-jira-host.com/"
projectCode = "TD"
username = "username"
@ -135,9 +136,8 @@ doormanConfig {
}
}
# Network map config
# Comment out this section if running without network map service
networkMapConfig {
networkMap {
cacheTimeout = 600000
signInterval = 10000
}

View File

@ -20,10 +20,10 @@ database {
h2port = 0
# Comment out this section if running without doorman service
doormanConfig{
doorman {
approveInterval = 10000
approveAll = false
jiraConfig{
jira {
address = "https://doorman-jira-host.com/"
projectCode = "TD"
username = "username"
@ -32,7 +32,7 @@ doormanConfig{
}
# Comment out this section if running without network map service
networkMapConfig{
networkMap {
cacheTimeout = 600000
signInterval = 10000
}

View File

@ -1,19 +1,31 @@
basedir = "."
device = "3001@192.168.0.1"
keySpecifier = -1
authMode = PASSWORD
csrSigning {
crlDistributionPoint = "http://test.com/revoked.crl"
validDays = 3650
rootKeyStoreFile = "dummyfile.jks"
rootKeyStorePassword = "trustpass"
csrCertCrlDistPoint = "http://test.com/revoked.crl"
doormanKeyGroup = "DEV.CORDACONNECT.OPS.CERT"
networkMapKeyGroup = "DEV.CORDACONNECT.OPS.NETMAP"
validDays = 3650
signAuthThreshold = 2
keyGenAuthThreshold = 2
authKeyFilePath = "./Administrator.key"
authKeyFilePassword = "Password"
autoUsername = "AUTO_USER"
signInterval = 10000
keyGroup = "DEV.CORDACONNECT.OPS.CERT"
authParameters {
mode = PASSWORD
password = "PASSWORD"
threshold = 2
}
}
networkMapSigning {
username = "TEST_USERNAME",
keyGroup = "DEV.CORDACONNECT.OPS.NETMAP"
authParameters {
mode = KEY_FILE
password = "PASSWORD"
keyFilePath = "./Administrator.KEY"
threshold = 2
}
}
h2port = 0
dataSourceProperties {
"dataSourceClassName" = org.h2.jdbcx.JdbcDataSource

View File

@ -5,8 +5,10 @@ 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.InputReader
import com.r3.corda.networkmanage.hsm.configuration.AuthenticationParameters
import com.r3.corda.networkmanage.hsm.configuration.DoormanCertificateParameters
import com.r3.corda.networkmanage.hsm.configuration.NetworkMapCertificateParameters
import com.r3.corda.networkmanage.hsm.configuration.Parameters
import com.r3.corda.networkmanage.hsm.generator.AuthMode
import com.r3.corda.networkmanage.hsm.generator.CertificateConfiguration
import com.r3.corda.networkmanage.hsm.generator.GeneratorParameters
import com.r3.corda.networkmanage.hsm.generator.UserAuthenticationParameters
@ -18,6 +20,8 @@ import org.junit.Rule
import org.junit.rules.TemporaryFolder
import java.nio.file.Path
import java.util.*
import com.r3.corda.networkmanage.hsm.authentication.AuthMode as SigningServiceAuthMode
import com.r3.corda.networkmanage.hsm.generator.AuthMode as GeneratorAuthMode
abstract class HsmBaseTest {
companion object {
@ -55,7 +59,7 @@ abstract class HsmBaseTest {
private fun createHsmUserConfigs(username: String): List<UserAuthenticationParameters> {
return listOf(UserAuthenticationParameters(
username = username,
authMode = AuthMode.PASSWORD,
authMode = GeneratorAuthMode.PASSWORD,
authToken = "INTEGRATION_TEST",
keyFilePassword = null))
}
@ -118,12 +122,27 @@ abstract class HsmBaseTest {
dataSourceProperties = mock(),
device = "${hsmSimulator.port}@${hsmSimulator.host}",
keySpecifier = 1,
csrSigning = DoormanCertificateParameters(
rootKeyStoreFile = rootKeyStoreFile,
rootKeyStorePassword = TRUSTSTORE_PASSWORD,
doormanKeyGroup = DOORMAN_CERT_KEY_GROUP,
networkMapKeyGroup = NETWORK_MAP_CERT_KEY_GROUP,
keyGroup = DOORMAN_CERT_KEY_GROUP,
validDays = 3650,
csrCertCrlDistPoint = "http://test.com/revoked.crl"
rootKeyStorePassword = TRUSTSTORE_PASSWORD,
crlDistributionPoint = "http://test.com/revoked.crl",
authParameters = AuthenticationParameters(
mode = SigningServiceAuthMode.PASSWORD,
threshold = 2
)
),
networkMapSigning = NetworkMapCertificateParameters(
username = "INTEGRATION_TEST",
keyGroup = NETWORK_MAP_CERT_KEY_GROUP,
authParameters = AuthenticationParameters(
mode = SigningServiceAuthMode.PASSWORD,
password = "INTEGRATION_TEST",
threshold = 2
)
)
)
}

View File

@ -144,7 +144,7 @@ class NodeRegistrationTest : IntegrationTest() {
serverAddress,
configureDatabase(makeTestDataSourceProperties(dbName), DatabaseConfig(runMigration = true)),
CertPathAndKey(listOf(csrCa.certificate, rootCaCert), csrCa.keyPair.private),
DoormanConfig(approveAll = true, jiraConfig = null, approveInterval = timeoutMillis),
DoormanConfig(approveAll = true, jira = null, approveInterval = timeoutMillis),
networkParameters?.let {
NetworkMapStartParams(
LocalSigner(networkMapCa),

View File

@ -14,7 +14,11 @@ class HsmAuthenticatorTest : HsmBaseTest() {
// given
val userInput = givenHsmUserAuthenticationInput()
val hsmSigningServiceConfig = createHsmSigningServiceConfig()
val authenticator = Authenticator(provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.doormanKeyGroup), inputReader = userInput)
val doormanCertificateConfig = hsmSigningServiceConfig.csrSigning!!
val authenticator = Authenticator(provider = createProvider(
doormanCertificateConfig.keyGroup,
hsmSigningServiceConfig.keySpecifier,
hsmSigningServiceConfig.device), inputReader = userInput)
val executed = AtomicBoolean(false)
// when

View File

@ -49,12 +49,15 @@ class HsmPermissionTest : HsmBaseTest() {
val hsmSigningServiceConfig = createHsmSigningServiceConfig()
val signer = HsmCsrSigner(
mock(),
hsmSigningServiceConfig.loadRootKeyStore(),
hsmSigningServiceConfig.csrSigning!!.loadRootKeyStore(),
"",
null,
3650,
Authenticator(
provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.doormanKeyGroup),
provider = createProvider(
hsmSigningServiceConfig.csrSigning!!.keyGroup,
hsmSigningServiceConfig.keySpecifier,
hsmSigningServiceConfig.device),
inputReader = userInput)
)
@ -102,12 +105,15 @@ class HsmPermissionTest : HsmBaseTest() {
val hsmSigningServiceConfig = createHsmSigningServiceConfig()
val signer = HsmCsrSigner(
mock(),
hsmSigningServiceConfig.loadRootKeyStore(),
hsmSigningServiceConfig.csrSigning!!.loadRootKeyStore(),
"trustpass",
null,
3650,
Authenticator(
provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.doormanKeyGroup),
provider = createProvider(
hsmSigningServiceConfig.csrSigning!!.keyGroup,
hsmSigningServiceConfig.keySpecifier,
hsmSigningServiceConfig.device),
inputReader = userInput)
)

View File

@ -62,14 +62,18 @@ class HsmSigningServiceTest : HsmBaseTest() {
// given HSM CSR signer
val hsmSigningServiceConfig = createHsmSigningServiceConfig()
val doormanCertificateConfig = hsmSigningServiceConfig.csrSigning!!
val signer = HsmCsrSigner(
mock(),
hsmSigningServiceConfig.loadRootKeyStore(),
doormanCertificateConfig.loadRootKeyStore(),
"",
null,
3650,
Authenticator(
provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.doormanKeyGroup),
provider = createProvider(
doormanCertificateConfig.keyGroup,
hsmSigningServiceConfig.keySpecifier,
hsmSigningServiceConfig.device),
inputReader = userInput)
)
@ -119,8 +123,12 @@ class HsmSigningServiceTest : HsmBaseTest() {
// given HSM network map signer
val hsmSigningServiceConfig = createHsmSigningServiceConfig()
val networkMapCertificateConfig = hsmSigningServiceConfig.networkMapSigning!!
val hsmDataSigner = HsmSigner(Authenticator(
provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.networkMapKeyGroup),
provider = createProvider(
networkMapCertificateConfig.keyGroup,
hsmSigningServiceConfig.keySpecifier,
hsmSigningServiceConfig.device),
inputReader = userInput))
val database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true))

View File

@ -92,7 +92,7 @@ class SigningServiceIntegrationTest : HsmBaseTest() {
hostAndPort = NetworkHostAndPort(HOST, 0),
database = database,
csrCertPathAndKey = null,
doormanServiceParameter = DoormanConfig(approveAll = true, approveInterval = 2.seconds.toMillis(), jiraConfig = null),
doormanServiceParameter = DoormanConfig(approveAll = true, approveInterval = 2.seconds.toMillis(), jira = null),
startNetworkMap = null)
val doormanHostAndPort = server.hostAndPort
// Start Corda network registration.

View File

@ -21,23 +21,32 @@ class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private
// in current network map.
val latestNetworkParameters = networkMapStorage.getLatestNetworkParameters()
if (latestNetworkParameters == null) {
logger.info("No network parameters present")
logger.debug("No network parameters present")
return
}
logger.debug("Fetching current network map parameters...")
val currentNetworkParameters = networkMapStorage.getNetworkParametersOfNetworkMap()
logger.debug("Retrieved network map parameters: $currentNetworkParameters")
if (currentNetworkParameters?.verified() != latestNetworkParameters) {
persistSignedNetworkParameters(latestNetworkParameters)
} else {
logger.debug("Network map parameters up-to-date. Skipping signing.")
}
logger.debug("Fetching current network map...")
val currentSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
logger.debug("Fetching node info hashes with VALID certificates...")
val nodeInfoHashes = networkMapStorage.getNodeInfoHashes(CertificateStatus.VALID)
logger.debug("Retrieved node info hashes: $nodeInfoHashes")
val newNetworkMap = NetworkMap(nodeInfoHashes, latestNetworkParameters.serialize().hash)
val serialisedNetworkMap = newNetworkMap.serialize()
if (serialisedNetworkMap != currentSignedNetworkMap?.raw) {
logger.info("Signing a new network map: $newNetworkMap")
logger.debug("Creating a new signed network map: ${serialisedNetworkMap.hash}")
val newSignedNetworkMap = SignedDataWithCert(serialisedNetworkMap, signer.signBytes(serialisedNetworkMap.bytes))
networkMapStorage.saveNetworkMap(newSignedNetworkMap)
logger.debug("Signed network map saved")
} else {
logger.debug("Current network map is up-to-date. Skipping signing.")
}
}
@ -45,5 +54,6 @@ class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private
logger.info("Signing and persisting network parameters: $networkParameters")
val digitalSignature = signer.signObject(networkParameters).sig
networkMapStorage.saveNetworkParameters(networkParameters, digitalSignature)
logger.info("Signed network map parameters saved.")
}
}

View File

@ -19,8 +19,8 @@ data class NetworkManagementServerParameters(// TODO: Move local signing to sign
val database: DatabaseConfig = DatabaseConfig(),
val mode: Mode,
val doormanConfig: DoormanConfig?,
val networkMapConfig: NetworkMapConfig?,
val doorman: DoormanConfig?,
val networkMap: NetworkMapConfig?,
val updateNetworkParameters: Path?,
val trustStorePassword: String?,
@ -51,7 +51,7 @@ data class NetworkManagementServerParameters(// TODO: Move local signing to sign
}
data class DoormanConfig(val approveAll: Boolean = false,
val jiraConfig: JiraConfig? = null,
val jira: JiraConfig? = null,
val approveInterval: Long = NetworkManagementServerParameters.DEFAULT_APPROVE_INTERVAL.toMillis())
data class NetworkMapConfig(val cacheTimeout: Long,
@ -59,9 +59,10 @@ data class NetworkMapConfig(val cacheTimeout: Long,
val signInterval: Long = NetworkManagementServerParameters.DEFAULT_SIGN_INTERVAL.toMillis())
enum class Mode {
// TODO CA_KEYGEN now also generates the nework map cert, so it should be renamed.
// TODO CA_KEYGEN now also generates the network map cert, so it should be renamed.
DOORMAN,
CA_KEYGEN, ROOT_KEYGEN
CA_KEYGEN,
ROOT_KEYGEN
}
data class JiraConfig(

View File

@ -71,15 +71,15 @@ fun main(args: Array<String>) {
val networkManagementServer = NetworkManagementServer()
val networkParameters = updateNetworkParameters?.let {
// TODO This check shouldn't be needed. Fix up the config design.
requireNotNull(networkMapConfig) { "'networkMapConfig' config is required for applying network parameters" }
requireNotNull(networkMap) { "'networkMapConfig' config is required for applying network parameters" }
println("Parsing network parameters from '${it.toAbsolutePath()}'...")
parseNetworkParametersFrom(it)
}
val networkMapStartParams = networkMapConfig?.let {
val networkMapStartParams = networkMap?.let {
NetworkMapStartParams(csrAndNetworkMap?.second, networkParameters, it)
}
networkManagementServer.start(NetworkHostAndPort(host, port), persistence, csrAndNetworkMap?.first, doormanConfig, networkMapStartParams)
networkManagementServer.start(NetworkHostAndPort(host, port), persistence, csrAndNetworkMap?.first, doorman, networkMapStartParams)
Runtime.getRuntime().addShutdownHook(thread(start = false) {
networkManagementServer.close()

View File

@ -83,13 +83,14 @@ class NetworkManagementServer : Closeable {
serverStatus: NetworkManagementServerStatus): RegistrationWebService {
logger.info("Starting Doorman server.")
val requestService = if (config.approveAll) {
require(config.jira == null) { "Jira configuration cannot be specified when the approveAll parameter is set to true." }
logger.warn("Doorman server is in 'Approve All' mode, this will approve all incoming certificate signing requests.")
ApproveAllCertificateRequestStorage(PersistentCertificateRequestStorage(database))
} else {
PersistentCertificateRequestStorage(database)
}
val jiraConfig = config.jiraConfig
val jiraConfig = config.jira
val requestProcessor = if (jiraConfig != null) {
val jiraWebAPI = AsynchronousJiraRestClientFactory().createWithBasicHttpAuthentication(URI(jiraConfig.address), jiraConfig.username, jiraConfig.password)
val jiraClient = JiraClient(jiraWebAPI, jiraConfig.projectCode)

View File

@ -7,7 +7,11 @@ import net.corda.core.internal.createDirectories
import net.corda.core.internal.div
import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509KeyStore
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_INTERMEDIATE_CA
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
import net.corda.nodeapi.internal.crypto.X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME
import net.corda.nodeapi.internal.crypto.X509Utilities.createCertificate
import net.corda.nodeapi.internal.crypto.X509Utilities.createSelfSignedCACertificate
import java.nio.file.Path
import javax.security.auth.x500.X500Principal
import kotlin.system.exitProcess
@ -36,19 +40,19 @@ fun generateRootKeyPair(rootStoreFile: Path, rootKeystorePass: String?, rootPriv
val rootStore = X509KeyStore.fromFile(rootStoreFile, rootKeystorePassword, createNew = true)
val rootPrivateKeyPassword = rootPrivateKeyPass ?: readPassword("Root Private Key Password: ")
if (X509Utilities.CORDA_ROOT_CA in rootStore) {
println("${X509Utilities.CORDA_ROOT_CA} already exists in keystore, process will now terminate.")
println(rootStore.getCertificate(X509Utilities.CORDA_ROOT_CA))
if (CORDA_ROOT_CA in rootStore) {
println("$CORDA_ROOT_CA already exists in keystore, process will now terminate.")
println(rootStore.getCertificate(CORDA_ROOT_CA))
exitProcess(1)
}
val selfSignKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val selfSignKey = Crypto.generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME)
// TODO Make the cert subject configurable
val rootCert = X509Utilities.createSelfSignedCACertificate(
val rootCert = createSelfSignedCACertificate(
X500Principal("CN=Corda Root CA,$CORDA_X500_BASE"),
selfSignKey)
rootStore.update {
setPrivateKey(X509Utilities.CORDA_ROOT_CA, selfSignKey.private, listOf(rootCert), rootPrivateKeyPassword)
setPrivateKey(CORDA_ROOT_CA, selfSignKey.private, listOf(rootCert), rootPrivateKeyPassword)
}
val trustStorePath = (rootStoreFile.parent / "distribute-nodes").createDirectories() / NETWORK_ROOT_TRUSTSTORE_FILENAME
@ -56,7 +60,7 @@ fun generateRootKeyPair(rootStoreFile: Path, rootKeystorePass: String?, rootPriv
val networkRootTrustPassword = networkRootTrustPass ?: readPassword("Network Root Trust Store Password: ")
X509KeyStore.fromFile(trustStorePath, networkRootTrustPassword, createNew = true).update {
setCertificate(X509Utilities.CORDA_ROOT_CA, rootCert)
setCertificate(CORDA_ROOT_CA, rootCert)
}
println("Trust store for distribution to nodes created in $trustStorePath")
@ -71,7 +75,7 @@ fun generateSigningKeyPairs(keystoreFile: Path, rootStoreFile: Path, rootKeystor
val rootPrivateKeyPassword = rootPrivateKeyPass ?: readPassword("Root private key password: ")
val rootKeyStore = X509KeyStore.fromFile(rootStoreFile, rootKeystorePassword)
val rootKeyPairAndCert = rootKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_ROOT_CA, rootPrivateKeyPassword)
val rootKeyPairAndCert = rootKeyStore.getCertificateAndKeyPair(CORDA_ROOT_CA, rootPrivateKeyPassword)
val keyStorePassword = keystorePass ?: readPassword("Key store Password: ")
val privateKeyPassword = caPrivateKeyPass ?: readPassword("Private key Password: ")
@ -87,7 +91,7 @@ fun generateSigningKeyPairs(keystoreFile: Path, rootStoreFile: Path, rootKeystor
}
val keyPair = Crypto.generateKeyPair(signatureScheme)
val cert = X509Utilities.createCertificate(
val cert = createCertificate(
certificateType,
rootKeyPairAndCert.certificate,
rootKeyPairAndCert.keyPair,
@ -104,10 +108,10 @@ fun generateSigningKeyPairs(keystoreFile: Path, rootStoreFile: Path, rootKeystor
}
storeCertIfAbsent(
X509Utilities.CORDA_INTERMEDIATE_CA,
CORDA_INTERMEDIATE_CA,
CertificateType.INTERMEDIATE_CA,
X500Principal("CN=Corda Doorman CA,$CORDA_X500_BASE"),
X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
DEFAULT_TLS_SIGNATURE_SCHEME)
storeCertIfAbsent(
CORDA_NETWORK_MAP,

View File

@ -1,176 +1,53 @@
package com.r3.corda.networkmanage.hsm
import com.google.common.util.concurrent.MoreExecutors
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
import com.r3.corda.networkmanage.common.persistence.PersistentNetworkMapStorage
import com.r3.corda.networkmanage.common.persistence.configureDatabase
import com.r3.corda.networkmanage.common.signer.NetworkMapSigner
import com.r3.corda.networkmanage.common.utils.ShowHelpException
import com.r3.corda.networkmanage.common.utils.initialiseSerialization
import com.r3.corda.networkmanage.hsm.authentication.AuthMode
import com.r3.corda.networkmanage.hsm.authentication.Authenticator
import com.r3.corda.networkmanage.hsm.authentication.createProvider
import com.r3.corda.networkmanage.hsm.configuration.Parameters
import com.r3.corda.networkmanage.hsm.configuration.parseParameters
import com.r3.corda.networkmanage.hsm.menu.Menu
import com.r3.corda.networkmanage.hsm.persistence.ApprovedCertificateRequestData
import com.r3.corda.networkmanage.hsm.persistence.DBSignedCertificateRequestStorage
import com.r3.corda.networkmanage.hsm.signer.HsmCsrSigner
import com.r3.corda.networkmanage.hsm.signer.HsmSigner
import com.r3.corda.networkmanage.hsm.utils.mapCryptoServerException
import com.r3.corda.networkmanage.hsm.processor.CsrProcessor
import com.r3.corda.networkmanage.hsm.processor.NetworkMapProcessor
import org.apache.logging.log4j.LogManager
import org.bouncycastle.jce.provider.BouncyCastleProvider
import java.security.Security
import java.time.Duration
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit.MILLISECONDS
import java.util.concurrent.TimeUnit.SECONDS
import javax.crypto.Cipher
private val log = LogManager.getLogger("com.r3.corda.networkmanage.hsm.Main")
private val logger = LogManager.getLogger("com.r3.corda.networkmanage.hsm.Main")
fun main(args: Array<String>) {
// Grabbed from https://stackoverflow.com/questions/7953567/checking-if-unlimited-cryptography-is-available
if (Cipher.getMaxAllowedKeyLength("AES") < 256) {
System.err.println("Unlimited Strength Jurisdiction Policy Files must be installed, see http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html")
System.exit(1)
}
parseParameters(*args).run {
try {
run(parseParameters(*args))
} catch (e: ShowHelpException) {
e.errorMessage?.let(::println)
e.parser.printHelpOn(System.out)
// Validate
// Grabbed from https://stackoverflow.com/questions/7953567/checking-if-unlimited-cryptography-is-available
require(Cipher.getMaxAllowedKeyLength("AES") >= 256) {
"Unlimited Strength Jurisdiction Policy Files must be installed, see http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html"
}
require(csrSigning != null || networkMapSigning != null) {
"Either network map or certificate signing request certificate parameters must be specified."
}
requireNotNull(dataSourceProperties)
fun run(parameters: Parameters) {
parameters.run {
// Ensure the BouncyCastle provider is installed
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(BouncyCastleProvider())
}
// Create DB connection.
checkNotNull(dataSourceProperties)
initialiseSerialization()
val database = configureDatabase(dataSourceProperties, databaseConfig)
val csrStorage = DBSignedCertificateRequestStorage(database)
val hsmSigner = HsmSigner(
Authenticator(
AuthMode.KEY_FILE,
autoUsername,
authKeyFilePath,
authKeyFilePassword,
signAuthThreshold,
provider = createProvider(networkMapKeyGroup)))
val networkMapStorage = PersistentNetworkMapStorage(database)
val scheduler = Executors.newSingleThreadScheduledExecutor()
startNetworkingMapSigningPolling(networkMapStorage, hsmSigner, scheduler, Duration.ofMillis(signInterval))
val sign: (List<ApprovedCertificateRequestData>) -> Unit = {
val signer = HsmCsrSigner(
csrStorage,
loadRootKeyStore(),
csrCertCrlDistPoint,
csrCertCrlIssuer,
validDays,
Authenticator(
authMode,
autoUsername,
authKeyFilePath,
authKeyFilePassword,
signAuthThreshold,
provider = createProvider(doormanKeyGroup)))
signer.sign(it)
// Create DB connection.
val persistence = configureDatabase(dataSourceProperties, database)
if (networkMapSigning != null) {
NetworkMapProcessor(networkMapSigning, device, keySpecifier, persistence).run()
}
Menu().withExceptionHandler(::processError).addItem("1", "Sign all approved and unsigned CSRs", {
val approved = csrStorage.getApprovedRequests()
if (approved.isNotEmpty()) {
if (confirmedSign(approved)) {
sign(approved)
}
} else {
println("There is no approved CSR")
}
}).addItem("2", "List all approved and unsigned CSRs", {
val approved = csrStorage.getApprovedRequests()
if (approved.isNotEmpty()) {
println("Approved CSRs:")
approved.forEachIndexed { index, item -> println("${index + 1}. ${item.request.subject}") }
Menu().withExceptionHandler(::processError).setExitOption("3", "Go back").
addItem("1", "Sign all listed CSRs", {
if (confirmedSign(approved)) {
sign(approved)
}
}, isTerminating = true).
addItem("2", "Select and sign CSRs", {
val selectedItems = getSelection(approved)
if (confirmedSign(selectedItems)) {
sign(selectedItems)
}
}, isTerminating = true).showMenu()
} else {
println("There is no approved and unsigned CSR")
}
}).showMenu()
MoreExecutors.shutdownAndAwaitTermination(scheduler, 30, SECONDS)
}
}
private fun startNetworkingMapSigningPolling(networkMapStorage: NetworkMapStorage,
signer: HsmSigner,
executor: ScheduledExecutorService,
signingPeriod: Duration) {
val networkMapSigner = NetworkMapSigner(networkMapStorage, signer)
log.info("Starting the network map signing thread: sign interval ${signingPeriod.toMillis()} ms")
executor.scheduleAtFixedRate({
if (csrSigning != null) {
try {
networkMapSigner.signNetworkMap()
CsrProcessor(csrSigning, device, keySpecifier, persistence).showMenu()
} catch (e: ShowHelpException) {
e.errorMessage?.let(::println)
e.parser.printHelpOn(System.out)
}
}
} catch (e: Exception) {
log.error("Exception thrown while signing network map", e)
logger.error("Error while starting the HSM Signing service.", e)
}
}, signingPeriod.toMillis(), signingPeriod.toMillis(), MILLISECONDS)
}
private fun processError(exception: Exception) {
val processed = mapCryptoServerException(exception)
System.err.println("An error occurred:")
processed.printStackTrace()
}
private fun confirmedSign(selectedItems: List<ApprovedCertificateRequestData>): Boolean {
println("Are you sure you want to sign the following requests:")
selectedItems.forEachIndexed { index, data ->
println("${index + 1} ${data.request.subject}")
}
var result = false
Menu().addItem("Y", "Yes", { result = true }, true).setExitOption("N", "No").showMenu()
return result
}
private fun getSelection(toSelect: List<ApprovedCertificateRequestData>): List<ApprovedCertificateRequestData> {
print("CSRs to be signed (comma separated list): ")
val line = readLine()
if (line == null) {
println("EOF reached")
return emptyList()
}
return try {
line.split(",").map {
val result = it.toInt() - 1
if (result > toSelect.size - 1) {
throw IllegalArgumentException("Selected ${result + 1} item is out of bounds")
} else {
toSelect[result]
}
}
} catch (exception: Exception) {
println(exception.message)
emptyList()
}
}

View File

@ -2,7 +2,6 @@ package com.r3.corda.networkmanage.hsm.authentication
import CryptoServerJCE.CryptoServerProvider
import com.r3.corda.networkmanage.common.signer.AuthenticationException
import com.r3.corda.networkmanage.hsm.configuration.Parameters
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.nio.file.Path
@ -116,8 +115,14 @@ data class CryptoServerProviderConfig(
/**
* Creates an instance of [CryptoServerProvider] that corresponds to the HSM.
*
* @param keyGroup HSM key group.
* @param keySpecifier HSM key specifier.
* @param device HSM device address.
*
* @return preconfigured instance of [CryptoServerProvider]
*/
fun Parameters.createProvider(keyGroup: String): CryptoServerProvider {
fun createProvider(keyGroup: String, keySpecifier: Int, device: String): CryptoServerProvider {
val config = CryptoServerProviderConfig(
Device = device,
KeyGroup = keyGroup,
@ -126,6 +131,13 @@ fun Parameters.createProvider(keyGroup: String): CryptoServerProvider {
return createProvider(config)
}
/**
* Creates an instance of [CryptoServerProvider] configured accordingly to the passed configuration.
*
* @param config crypto server provider configuration.
*
* @return preconfigured instance of [CryptoServerProvider]
*/
fun createProvider(config: CryptoServerProviderConfig): CryptoServerProvider {
val cfgBuffer = ByteArrayOutputStream()
val writer = cfgBuffer.writer(Charsets.UTF_8)

View File

@ -6,7 +6,6 @@ import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigParseOptions
import net.corda.core.internal.div
import net.corda.core.internal.isRegularFile
import net.corda.core.utilities.minutes
import net.corda.nodeapi.internal.config.parseAs
import net.corda.nodeapi.internal.crypto.X509KeyStore
import net.corda.nodeapi.internal.persistence.DatabaseConfig
@ -15,47 +14,45 @@ import java.nio.file.Paths
import java.util.*
/**
* Configuration parameters.
* Configuration parameters. Those are general configuration parameters shared with both
* network map and certificate signing requests processes.
*/
data class Parameters(val dataSourceProperties: Properties,
val databaseConfig: DatabaseConfig = DatabaseConfig(),
val device: String = DEFAULT_DEVICE,
// TODO this needs cleaning up after the config-file-only support is implemented
val database: DatabaseConfig = DatabaseConfig(),
val device: String,
val keySpecifier: Int,
val networkMapSigning: NetworkMapCertificateParameters? = null,
val csrSigning: DoormanCertificateParameters? = null)
/**
* Network map signing process specific parameters.
*/
data class NetworkMapCertificateParameters(val username: String,
val keyGroup: String,
val authParameters: AuthenticationParameters)
/**
* Certificate signing requests process specific parameters.
*/
data class DoormanCertificateParameters(val crlDistributionPoint: String,
val keyGroup:String,
val validDays: Int,
val rootKeyStoreFile: Path,
val rootKeyStorePassword: String,
val doormanKeyGroup: String,
val networkMapKeyGroup: String,
val keySpecifier: Int = DEFAULT_KEY_SPECIFIER,
val csrCertCrlDistPoint: String,
val csrCertCrlIssuer: String? = DEFAULT_CSR_CERT_CRL_ISSUER, // X500 name of the issuing authority e.g. "L=New York, C=US, OU=Org Unit, CN=Service Name",
// if null parent CA is is considered as an issuer.
val validDays: Int,
val signAuthThreshold: Int = DEFAULT_SIGN_AUTH_THRESHOLD,
val keyGenAuthThreshold: Int = DEFAULT_KEY_GEN_AUTH_THRESHOLD,
val authMode: AuthMode = DEFAULT_AUTH_MODE,
val authKeyFilePath: Path? = DEFAULT_KEY_FILE_PATH,
val authKeyFilePassword: String? = DEFAULT_KEY_FILE_PASSWORD,
val autoUsername: String? = DEFAULT_AUTO_USERNAME,
// TODO Change this to Duration in the future.
val signInterval: Long = DEFAULT_SIGN_INTERVAL) {
companion object {
val DEFAULT_DEVICE = "3001@127.0.0.1"
val DEFAULT_AUTH_MODE = AuthMode.PASSWORD
val DEFAULT_SIGN_AUTH_THRESHOLD = 2
val DEFAULT_KEY_GEN_AUTH_THRESHOLD = 2
val DEFAULT_KEY_SPECIFIER = 1
val DEFAULT_KEY_FILE_PATH: Path? = null //Paths.get("/Users/michalkit/WinDev1706Eval/Shared/TEST4.key")
val DEFAULT_KEY_FILE_PASSWORD: String? = null
val DEFAULT_AUTO_USERNAME: String? = null
val DEFAULT_SIGN_INTERVAL = 1.minutes.toMillis()
val DEFAULT_CSR_CERT_CRL_ISSUER: String? = null
}
val authParameters: AuthenticationParameters) {
fun loadRootKeyStore(createNew: Boolean = false): X509KeyStore {
return X509KeyStore.fromFile(rootKeyStoreFile, rootKeyStorePassword, createNew)
}
}
/**
* Authentication related parameters.
*/
data class AuthenticationParameters(val mode: AuthMode,
val password: String? = null, // This is either HSM password or key file password, depending on the mode.
val keyFilePath: Path? = null,
val threshold: Int)
/**
* Parses the list of arguments and produces an instance of [Parameters].
* @param args list of strings corresponding to program arguments

View File

@ -0,0 +1,117 @@
package com.r3.corda.networkmanage.hsm.processor
import com.r3.corda.networkmanage.hsm.authentication.Authenticator
import com.r3.corda.networkmanage.hsm.authentication.createProvider
import com.r3.corda.networkmanage.hsm.configuration.DoormanCertificateParameters
import com.r3.corda.networkmanage.hsm.menu.Menu
import com.r3.corda.networkmanage.hsm.persistence.ApprovedCertificateRequestData
import com.r3.corda.networkmanage.hsm.persistence.DBSignedCertificateRequestStorage
import com.r3.corda.networkmanage.hsm.signer.HsmCsrSigner
import com.r3.corda.networkmanage.hsm.utils.mapCryptoServerException
import net.corda.core.utilities.contextLogger
import net.corda.nodeapi.internal.persistence.CordaPersistence
class CsrProcessor(private val parameters: DoormanCertificateParameters,
private val device: String,
private val keySpecifier: Int,
private val database: CordaPersistence) {
companion object {
val logger = contextLogger()
}
private val auth = parameters.authParameters
fun showMenu() {
val csrStorage = DBSignedCertificateRequestStorage(database)
val sign: (List<ApprovedCertificateRequestData>) -> Unit = {
val signer = parameters.run {
HsmCsrSigner(
csrStorage,
loadRootKeyStore(),
crlDistributionPoint,
null,
validDays,
Authenticator(
provider = createProvider(parameters.keyGroup, keySpecifier, device),
mode = auth.mode,
authStrengthThreshold = auth.threshold))
}
logger.debug("Signing requests: $it")
signer.sign(it)
}
Menu().withExceptionHandler(this::processError).setExitOption("3", "Quit").addItem("1", "Sign all approved and unsigned CSRs",
{
logger.debug("Fetching approved requests...")
val approved = csrStorage.getApprovedRequests()
logger.debug("Approved requests fetched: $approved")
if (approved.isNotEmpty()) {
if (confirmedSign(approved)) {
sign(approved)
}
} else {
println("There is no approved CSR")
}
}).addItem("2", "List all approved and unsigned CSRs",
{
logger.debug("Fetching approved requests...")
val approved = csrStorage.getApprovedRequests()
logger.debug("Approved requests fetched: $approved")
if (approved.isNotEmpty()) {
println("Approved CSRs:")
approved.forEachIndexed { index, item -> println("${index + 1}. ${item.request.subject}") }
Menu().withExceptionHandler(this::processError).setExitOption("3", "Go back").
addItem("1", "Sign all listed CSRs", {
if (confirmedSign(approved)) {
sign(approved)
}
}, isTerminating = true).
addItem("2", "Select and sign CSRs", {
val selectedItems = getSelection(approved)
if (confirmedSign(selectedItems)) {
sign(selectedItems)
}
}, isTerminating = true).showMenu()
} else {
println("There is no approved and unsigned CSR")
}
}).showMenu()
}
private fun confirmedSign(selectedItems: List<ApprovedCertificateRequestData>): Boolean {
println("Are you sure you want to sign the following requests:")
selectedItems.forEachIndexed { index, data ->
println("${index + 1} ${data.request.subject}")
}
var result = false
Menu().addItem("Y", "Yes", { result = true }, true).setExitOption("N", "No").showMenu()
return result
}
private fun getSelection(toSelect: List<ApprovedCertificateRequestData>): List<ApprovedCertificateRequestData> {
print("CSRs to be signed (comma separated list): ")
val line = readLine()
if (line == null) {
println("EOF reached")
return emptyList()
}
return try {
line.split(",").map {
val result = it.toInt() - 1
if (result > toSelect.size - 1) {
throw IllegalArgumentException("Selected ${result + 1} item is out of bounds")
} else {
toSelect[result]
}
}
} catch (exception: Exception) {
println(exception.message)
emptyList()
}
}
fun processError(exception: Exception) {
val processed = mapCryptoServerException(exception)
System.err.println("An error occurred:")
processed.printStackTrace()
}
}

View File

@ -0,0 +1,52 @@
package com.r3.corda.networkmanage.hsm.processor
import com.r3.corda.networkmanage.common.persistence.PersistentNetworkMapStorage
import com.r3.corda.networkmanage.common.signer.NetworkMapSigner
import com.r3.corda.networkmanage.hsm.authentication.AuthMode
import com.r3.corda.networkmanage.hsm.authentication.Authenticator
import com.r3.corda.networkmanage.hsm.authentication.createProvider
import com.r3.corda.networkmanage.hsm.configuration.NetworkMapCertificateParameters
import com.r3.corda.networkmanage.hsm.signer.HsmSigner
import net.corda.core.utilities.contextLogger
import net.corda.nodeapi.internal.persistence.CordaPersistence
class NetworkMapProcessor(private val parameters: NetworkMapCertificateParameters,
private val device: String,
private val keySpecifier: Int,
private val database: CordaPersistence) {
companion object {
val logger = contextLogger()
}
init {
parameters.authParameters.run {
requireNotNull(password)
require(mode != AuthMode.CARD_READER)
if (mode == AuthMode.KEY_FILE) {
require(keyFilePath != null) { "Key file path cannot be null when authentication mode is ${AuthMode.KEY_FILE}" }
}
}
}
fun run() {
logger.info("Starting network map processor.")
parameters.run {
val networkMapStorage = PersistentNetworkMapStorage(database)
val signer = HsmSigner(
Authenticator(
AuthMode.KEY_FILE,
username,
authParameters.keyFilePath,
authParameters.password,
authParameters.threshold,
provider = createProvider(keyGroup, keySpecifier, device)))
val networkMapSigner = NetworkMapSigner(networkMapStorage, signer)
try {
logger.info("Executing network map signing...")
networkMapSigner.signNetworkMap()
} catch (e: Exception) {
logger.error("Exception thrown while signing network map", e)
}
}
}
}

View File

@ -6,10 +6,14 @@ import com.r3.corda.networkmanage.hsm.persistence.SignedCertificateRequestStorag
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.createClientCertificate
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.getAndInitializeKeyStore
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.retrieveCertAndKeyPair
import net.corda.core.utilities.contextLogger
import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509KeyStore
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_INTERMEDIATE_CA
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
import net.corda.nodeapi.internal.crypto.X509Utilities.buildCertPath
import org.bouncycastle.asn1.x500.X500Name
import java.io.PrintStream
/**
* Encapsulates certificate signing logic
@ -19,7 +23,12 @@ class HsmCsrSigner(private val storage: SignedCertificateRequestStorage,
private val csrCertCrlDistPoint: String,
private val csrCertCrlIssuer: String?,
private val validDays: Int,
private val authenticator: Authenticator) : CertificateSigningRequestSigner {
private val authenticator: Authenticator,
private val printStream: PrintStream = System.out) : CertificateSigningRequestSigner {
companion object {
val logger = contextLogger()
}
/**
* Signs the provided list of approved certificate signing requests. By signature we mean creation of the client-level certificate
@ -33,11 +42,12 @@ class HsmCsrSigner(private val storage: SignedCertificateRequestStorage,
*/
override fun sign(toSign: List<ApprovedCertificateRequestData>) {
authenticator.connectAndAuthenticate { provider, signers ->
// This should be changed once we allow for more certificates in the chain. Preferably we should use
// keyStore.getCertificateChain(String) and assume entire chain is stored in the HSM (depending on the support).
val rootCert = rootKeyStore.getCertificate(X509Utilities.CORDA_ROOT_CA)
logger.debug("Retrieving the root certificate ${CORDA_ROOT_CA} from HSM...")
val rootCert = rootKeyStore.getCertificate(CORDA_ROOT_CA)
logger.debug("Initializing doorman key store...")
val keyStore = getAndInitializeKeyStore(provider)
val doormanCertAndKey = retrieveCertAndKeyPair(X509Utilities.CORDA_INTERMEDIATE_CA, keyStore)
logger.debug("Retrieving the doorman certificate $CORDA_INTERMEDIATE_CA from HSM...")
val doormanCertAndKey = retrieveCertAndKeyPair(CORDA_INTERMEDIATE_CA, keyStore)
toSign.forEach {
val nodeCaCert = createClientCertificate(
CertificateType.NODE_CA,
@ -47,12 +57,15 @@ class HsmCsrSigner(private val storage: SignedCertificateRequestStorage,
provider,
csrCertCrlDistPoint,
csrCertCrlIssuer?.let { X500Name(it) })
it.certPath = X509Utilities.buildCertPath(nodeCaCert, doormanCertAndKey.certificate, rootCert)
it.certPath = buildCertPath(nodeCaCert, doormanCertAndKey.certificate, rootCert)
}
logger.debug("Storing signed CSRs...")
storage.store(toSign, signers)
println("The following certificates have been signed by $signers:")
printStream.println("The following certificates have been signed by $signers:")
logger.debug("The following certificates have been signed by $signers:")
toSign.forEachIndexed { index, data ->
println("${index + 1} ${data.request.subject}")
printStream.println("${index + 1} ${data.request.subject}")
logger.debug("${index + 1} ${data.request.subject}")
}
}
}

View File

@ -6,6 +6,7 @@ import com.typesafe.config.ConfigException
import org.assertj.core.api.Assertions
import org.junit.Test
import java.io.File
import java.nio.file.Paths
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
@ -15,9 +16,18 @@ class ConfigurationTest : TestBase() {
@Test
fun `config file is parsed correctly`() {
val paramsWithPassword = parseParameters("--config-file", validConfigPath)
assertEquals(AuthMode.PASSWORD, paramsWithPassword.authMode)
assertEquals("3001@192.168.0.1", paramsWithPassword.device)
val parameters = parseParameters("--config-file", validConfigPath)
assertEquals("3001@192.168.0.1", parameters.device)
val doormanCertParameters = parameters.csrSigning!!
assertEquals(AuthMode.PASSWORD, doormanCertParameters.authParameters.mode)
assertEquals(2, doormanCertParameters.authParameters.threshold)
assertEquals(3650, doormanCertParameters.validDays)
val nmParams = parameters.networkMapSigning!!
assertEquals(AuthMode.KEY_FILE, nmParams.authParameters.mode)
assertEquals(Paths.get("./Administrator.KEY"), nmParams.authParameters.keyFilePath)
assertEquals(2, nmParams.authParameters.threshold)
assertEquals("PASSWORD", nmParams.authParameters.password)
assertEquals("TEST_USERNAME", nmParams.username)
}
@Test