mirror of
https://github.com/corda/corda.git
synced 2025-06-17 14:48:16 +00:00
Switching to reading the root certificate from the truststore (#449)
* Switching to reading the root certificate from the truststore * Addressing review comments
This commit is contained in:
@ -28,7 +28,9 @@ Allowed parameters are:
|
|||||||
:device: HSM connection string. It is of the following format 3001@127.0.0.1, where 3001 is the port number.
|
: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"
|
Default value: "3001@127.0.0.1"
|
||||||
|
|
||||||
:rootKeyGroup: HSM key group for the root certificate key. This parameter is vendor specific (see Utimaco docs).
|
: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).
|
:networkMapKeyGroup: HSM key group for the network map certificate key. This parameter is vendor specific (see Utimaco docs).
|
||||||
|
|
||||||
@ -38,12 +40,8 @@ Allowed parameters are:
|
|||||||
|
|
||||||
:rootPrivateKeyPassword: Private key password for the root certificate.
|
:rootPrivateKeyPassword: Private key password for the root certificate.
|
||||||
|
|
||||||
:rootCertificateName: Root certificate name. Default value: "cordarootca".
|
|
||||||
|
|
||||||
:csrPrivateKeyPassword: Private key password for the intermediate certificate used to sign certficate signing requests.
|
:csrPrivateKeyPassword: Private key password for the intermediate certificate used to sign certficate signing requests.
|
||||||
|
|
||||||
:csrCertificateName: Certificate signing requests intermediate certificate name. Default value: "cordaintermediateca".
|
|
||||||
|
|
||||||
:csrCertCrlDistPoint: Certificate revocation list location for the node CA certificate.
|
:csrCertCrlDistPoint: Certificate revocation list location for the node CA certificate.
|
||||||
|
|
||||||
: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".
|
: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".
|
||||||
@ -53,8 +51,6 @@ Allowed parameters are:
|
|||||||
|
|
||||||
:dataSourceProperties: Data source properties. It should describe (or point to) the Doorman database.
|
:dataSourceProperties: Data source properties. It should describe (or point to) the Doorman database.
|
||||||
|
|
||||||
:networkMapCertificateName: Network map intermediate certificate name. Default value: "cordaintermediateca_nm"
|
|
||||||
|
|
||||||
:networkMapPrivateKeyPassword: Private key password for the intermediate certificate used to sign the network map.
|
:networkMapPrivateKeyPassword: Private key password for the intermediate certificate used to sign the network map.
|
||||||
|
|
||||||
:validDays: Number of days issued signatures are valid for.
|
:validDays: Number of days issued signatures are valid for.
|
||||||
|
@ -2,11 +2,9 @@ basedir = "."
|
|||||||
device = "3001@192.168.0.1"
|
device = "3001@192.168.0.1"
|
||||||
keySpecifier = -1
|
keySpecifier = -1
|
||||||
authMode = PASSWORD
|
authMode = PASSWORD
|
||||||
rootCertificateName = "corda_root_ca"
|
rootKeyStoreFile = "dummyfile.jks"
|
||||||
csrCertificateName = "intermediate_ca"
|
rootKeyStorePassword = "trustpass"
|
||||||
csrCertCrlDistPoint = "http://test.com/revoked.crl"
|
csrCertCrlDistPoint = "http://test.com/revoked.crl"
|
||||||
networkMapCertificateName = "intermediate_ca"
|
|
||||||
rootKeyGroup = "DEV.CORDACONNECT.ROOT"
|
|
||||||
doormanKeyGroup = "DEV.CORDACONNECT.OPS.CERT"
|
doormanKeyGroup = "DEV.CORDACONNECT.OPS.CERT"
|
||||||
networkMapKeyGroup = "DEV.CORDACONNECT.OPS.NETMAP"
|
networkMapKeyGroup = "DEV.CORDACONNECT.OPS.NETMAP"
|
||||||
validDays = 3650
|
validDays = 3650
|
||||||
|
@ -11,27 +11,32 @@ import com.r3.corda.networkmanage.hsm.generator.CertificateConfiguration
|
|||||||
import com.r3.corda.networkmanage.hsm.generator.GeneratorParameters
|
import com.r3.corda.networkmanage.hsm.generator.GeneratorParameters
|
||||||
import com.r3.corda.networkmanage.hsm.generator.UserAuthenticationParameters
|
import com.r3.corda.networkmanage.hsm.generator.UserAuthenticationParameters
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
|
import net.corda.core.internal.div
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.rules.TemporaryFolder
|
import org.junit.rules.TemporaryFolder
|
||||||
|
import java.nio.file.Path
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
abstract class HsmBaseTest {
|
abstract class HsmBaseTest {
|
||||||
companion object {
|
companion object {
|
||||||
val ROOT_CERT_KEY_GROUP = "DEV.CORDACONNECT.ROOT"
|
const val ROOT_CERT_KEY_GROUP = "DEV.CORDACONNECT.ROOT"
|
||||||
val NETWORK_MAP_CERT_KEY_GROUP = "DEV.CORDACONNECT.OPS.NETMAP"
|
const val NETWORK_MAP_CERT_KEY_GROUP = "DEV.CORDACONNECT.OPS.NETMAP"
|
||||||
val DOORMAN_CERT_KEY_GROUP = "DEV.CORDACONNECT.OPS.CERT"
|
const val DOORMAN_CERT_KEY_GROUP = "DEV.CORDACONNECT.OPS.CERT"
|
||||||
val ROOT_CERT_SUBJECT = "CN=Corda Root CA, O=R3 HoldCo LLC, OU=Corda, L=New York, C=US"
|
const val ROOT_CERT_SUBJECT = "CN=Corda Root CA, O=R3 HoldCo LLC, OU=Corda, L=New York, C=US"
|
||||||
val NETWORK_MAP_CERT_SUBJECT = "CN=Corda Network Map, O=R3 HoldCo LLC, OU=Corda, L=New York, C=US"
|
const val NETWORK_MAP_CERT_SUBJECT = "CN=Corda Network Map, O=R3 HoldCo LLC, OU=Corda, L=New York, C=US"
|
||||||
val DOORMAN_CERT_SUBJECT = "CN=Corda Doorman CA, O=R3 HoldCo LLC, OU=Corda, L=New York, C=US"
|
const val DOORMAN_CERT_SUBJECT = "CN=Corda Doorman CA, O=R3 HoldCo LLC, OU=Corda, L=New York, C=US"
|
||||||
val HSM_USER_CONFIGS = listOf(UserAuthenticationParameters(
|
val HSM_USER_CONFIGS = listOf(UserAuthenticationParameters(
|
||||||
username = "INTEGRATION_TEST",
|
username = "INTEGRATION_TEST",
|
||||||
authMode = AuthMode.PASSWORD,
|
authMode = AuthMode.PASSWORD,
|
||||||
authToken = "INTEGRATION_TEST",
|
authToken = "INTEGRATION_TEST",
|
||||||
keyFilePassword = null))
|
keyFilePassword = null))
|
||||||
|
const val ROOT_KEYSTORE_PASSWORD: String = "trustpass"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected lateinit var rootKeyStoreFile: Path
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
@JvmField
|
@JvmField
|
||||||
val tempFolder = TemporaryFolder()
|
val tempFolder = TemporaryFolder()
|
||||||
@ -43,7 +48,8 @@ abstract class HsmBaseTest {
|
|||||||
private lateinit var dbName: String
|
private lateinit var dbName: String
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun generateRandomDbName() {
|
fun generateDbName() {
|
||||||
|
rootKeyStoreFile = tempFolder.root.toPath() / "truststore.jks"
|
||||||
dbName = random63BitValue().toString()
|
dbName = random63BitValue().toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,8 +57,8 @@ abstract class HsmBaseTest {
|
|||||||
return GeneratorParameters(
|
return GeneratorParameters(
|
||||||
hsmHost = hsmSimulator.host,
|
hsmHost = hsmSimulator.host,
|
||||||
hsmPort = hsmSimulator.port,
|
hsmPort = hsmSimulator.port,
|
||||||
trustStoreDirectory = tempFolder.root.toPath(),
|
trustStoreDirectory = rootKeyStoreFile.parent,
|
||||||
trustStorePassword = "",
|
trustStorePassword = ROOT_KEYSTORE_PASSWORD,
|
||||||
userConfigs = HSM_USER_CONFIGS,
|
userConfigs = HSM_USER_CONFIGS,
|
||||||
certConfig = certConfig
|
certConfig = certConfig
|
||||||
)
|
)
|
||||||
@ -79,16 +85,19 @@ abstract class HsmBaseTest {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
protected val hsmSigningServiceConfig = Parameters(
|
protected fun createHsmSigningServiceConfig(): Parameters {
|
||||||
|
return Parameters(
|
||||||
dataSourceProperties = mock(),
|
dataSourceProperties = mock(),
|
||||||
device = "${hsmSimulator.port}@${hsmSimulator.host}",
|
device = "${hsmSimulator.port}@${hsmSimulator.host}",
|
||||||
keySpecifier = 1,
|
keySpecifier = 1,
|
||||||
rootKeyGroup = ROOT_CERT_KEY_GROUP,
|
rootKeyStoreFile = rootKeyStoreFile,
|
||||||
|
rootKeyStorePassword = ROOT_KEYSTORE_PASSWORD,
|
||||||
doormanKeyGroup = DOORMAN_CERT_KEY_GROUP,
|
doormanKeyGroup = DOORMAN_CERT_KEY_GROUP,
|
||||||
networkMapKeyGroup = NETWORK_MAP_CERT_KEY_GROUP,
|
networkMapKeyGroup = NETWORK_MAP_CERT_KEY_GROUP,
|
||||||
validDays = 3650,
|
validDays = 3650,
|
||||||
csrCertCrlDistPoint = "http://test.com/revoked.crl"
|
csrCertCrlDistPoint = "http://test.com/revoked.crl"
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
protected fun givenHsmUserAuthenticationInput(): InputReader {
|
protected fun givenHsmUserAuthenticationInput(): InputReader {
|
||||||
val inputReader = mock<InputReader>()
|
val inputReader = mock<InputReader>()
|
||||||
@ -97,7 +106,7 @@ abstract class HsmBaseTest {
|
|||||||
return inputReader
|
return inputReader
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun makeTestDataSourceProperties(): Properties {
|
fun makeTestDataSourceProperties(): Properties {
|
||||||
return makeTestDataSourceProperties(dbName)
|
return makeTestDataSourceProperties(dbName)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,11 +13,12 @@ class HsmAuthenticatorTest : HsmBaseTest() {
|
|||||||
fun `Authenticator executes the block once user is successfully authenticated`() {
|
fun `Authenticator executes the block once user is successfully authenticated`() {
|
||||||
// given
|
// given
|
||||||
val userInput = givenHsmUserAuthenticationInput()
|
val userInput = givenHsmUserAuthenticationInput()
|
||||||
val authenticator = Authenticator(provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.rootKeyGroup), inputReader = userInput)
|
val hsmSigningServiceConfig = createHsmSigningServiceConfig()
|
||||||
|
val authenticator = Authenticator(provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.doormanKeyGroup), inputReader = userInput)
|
||||||
val executed = AtomicBoolean(false)
|
val executed = AtomicBoolean(false)
|
||||||
|
|
||||||
// when
|
// when
|
||||||
authenticator.connectAndAuthenticate { _, _, _ -> executed.set(true) }
|
authenticator.connectAndAuthenticate { _, _ -> executed.set(true) }
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertTrue(executed.get())
|
assertTrue(executed.get())
|
||||||
|
@ -16,19 +16,24 @@ import net.corda.core.crypto.Crypto.generateKeyPair
|
|||||||
import net.corda.core.identity.CordaX500Name.Companion.parse
|
import net.corda.core.identity.CordaX500Name.Companion.parse
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
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.DEFAULT_TLS_SIGNATURE_SCHEME
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities.createCertificateSigningRequest
|
import net.corda.nodeapi.internal.crypto.X509Utilities.createCertificateSigningRequest
|
||||||
|
import net.corda.nodeapi.internal.crypto.loadOrCreateKeyStore
|
||||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertNotNull
|
import kotlin.test.assertNotNull
|
||||||
|
|
||||||
class HsmSigningServiceTest : HsmBaseTest() {
|
class HsmSigningServiceTest : HsmBaseTest() {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
loadOrCreateKeyStore(rootKeyStoreFile, ROOT_KEYSTORE_PASSWORD)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `HSM signing service can sign CSR data`() {
|
fun `HSM signing service can sign CSR data`() {
|
||||||
// when root cert is created
|
// when root cert is created
|
||||||
@ -56,16 +61,15 @@ class HsmSigningServiceTest : HsmBaseTest() {
|
|||||||
val userInput = givenHsmUserAuthenticationInput()
|
val userInput = givenHsmUserAuthenticationInput()
|
||||||
|
|
||||||
// given HSM CSR signer
|
// given HSM CSR signer
|
||||||
|
val hsmSigningServiceConfig = createHsmSigningServiceConfig()
|
||||||
val signer = HsmCsrSigner(
|
val signer = HsmCsrSigner(
|
||||||
mock(),
|
mock(),
|
||||||
CORDA_INTERMEDIATE_CA,
|
hsmSigningServiceConfig.loadRootKeyStore(),
|
||||||
"",
|
"",
|
||||||
null,
|
null,
|
||||||
CORDA_ROOT_CA,
|
|
||||||
3650,
|
3650,
|
||||||
Authenticator(
|
Authenticator(
|
||||||
provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.doormanKeyGroup),
|
provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.doormanKeyGroup),
|
||||||
rootProvider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.rootKeyGroup),
|
|
||||||
inputReader = userInput)
|
inputReader = userInput)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -114,6 +118,7 @@ class HsmSigningServiceTest : HsmBaseTest() {
|
|||||||
val userInput = givenHsmUserAuthenticationInput()
|
val userInput = givenHsmUserAuthenticationInput()
|
||||||
|
|
||||||
// given HSM network map signer
|
// given HSM network map signer
|
||||||
|
val hsmSigningServiceConfig = createHsmSigningServiceConfig()
|
||||||
val hsmDataSigner = HsmSigner(Authenticator(
|
val hsmDataSigner = HsmSigner(Authenticator(
|
||||||
provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.networkMapKeyGroup),
|
provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.networkMapKeyGroup),
|
||||||
inputReader = userInput))
|
inputReader = userInput))
|
||||||
|
@ -10,6 +10,7 @@ import com.r3.corda.networkmanage.hsm.persistence.ApprovedCertificateRequestData
|
|||||||
import com.r3.corda.networkmanage.hsm.persistence.DBSignedCertificateRequestStorage
|
import com.r3.corda.networkmanage.hsm.persistence.DBSignedCertificateRequestStorage
|
||||||
import com.r3.corda.networkmanage.hsm.persistence.SignedCertificateRequestStorage
|
import com.r3.corda.networkmanage.hsm.persistence.SignedCertificateRequestStorage
|
||||||
import com.r3.corda.networkmanage.hsm.signer.HsmCsrSigner
|
import com.r3.corda.networkmanage.hsm.signer.HsmCsrSigner
|
||||||
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.createDirectories
|
import net.corda.core.internal.createDirectories
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
@ -49,8 +50,11 @@ class SigningServiceIntegrationTest : HsmBaseTest() {
|
|||||||
private lateinit var rootCaCert: X509Certificate
|
private lateinit var rootCaCert: X509Certificate
|
||||||
private lateinit var intermediateCa: CertificateAndKeyPair
|
private lateinit var intermediateCa: CertificateAndKeyPair
|
||||||
|
|
||||||
|
private lateinit var dbName: String
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
|
dbName = random63BitValue().toString()
|
||||||
timer = Timer()
|
timer = Timer()
|
||||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||||
rootCaCert = rootCa.certificate
|
rootCaCert = rootCa.certificate
|
||||||
|
@ -5,9 +5,9 @@ import com.r3.corda.networkmanage.common.persistence.CertificationRequestStorage
|
|||||||
import com.r3.corda.networkmanage.common.persistence.configureDatabase
|
import com.r3.corda.networkmanage.common.persistence.configureDatabase
|
||||||
import com.r3.corda.networkmanage.common.utils.*
|
import com.r3.corda.networkmanage.common.utils.*
|
||||||
import com.r3.corda.networkmanage.doorman.signer.LocalSigner
|
import com.r3.corda.networkmanage.doorman.signer.LocalSigner
|
||||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters.Companion.DEFAULT_CSR_CERTIFICATE_NAME
|
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
||||||
|
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||||
import net.corda.nodeapi.internal.network.NetworkParameters
|
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@ -24,7 +24,7 @@ private fun processKeyStore(parameters: NetworkManagementServerParameters): Pair
|
|||||||
val keyStorePassword = parameters.keystorePassword ?: readPassword("Key store password: ")
|
val keyStorePassword = parameters.keystorePassword ?: readPassword("Key store password: ")
|
||||||
val privateKeyPassword = parameters.caPrivateKeyPassword ?: readPassword("Private key password: ")
|
val privateKeyPassword = parameters.caPrivateKeyPassword ?: readPassword("Private key password: ")
|
||||||
val keyStore = X509KeyStore.fromFile(parameters.keystorePath, keyStorePassword)
|
val keyStore = X509KeyStore.fromFile(parameters.keystorePath, keyStorePassword)
|
||||||
val csrCertPathAndKey = keyStore.getCertPathAndKey(DEFAULT_CSR_CERTIFICATE_NAME, privateKeyPassword)
|
val csrCertPathAndKey = keyStore.getCertPathAndKey(X509Utilities.CORDA_INTERMEDIATE_CA, privateKeyPassword)
|
||||||
val networkMapSigner = LocalSigner(keyStore.getCertificateAndKeyPair(CORDA_NETWORK_MAP, privateKeyPassword))
|
val networkMapSigner = LocalSigner(keyStore.getCertificateAndKeyPair(CORDA_NETWORK_MAP, privateKeyPassword))
|
||||||
return Pair(csrCertPathAndKey, networkMapSigner)
|
return Pair(csrCertPathAndKey, networkMapSigner)
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package com.r3.corda.networkmanage.doorman
|
package com.r3.corda.networkmanage.doorman
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.common.utils.CORDA_NETWORK_MAP
|
import com.r3.corda.networkmanage.common.utils.CORDA_NETWORK_MAP
|
||||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters.Companion.DEFAULT_CSR_CERTIFICATE_NAME
|
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.crypto.SignatureScheme
|
import net.corda.core.crypto.SignatureScheme
|
||||||
import net.corda.core.internal.createDirectories
|
import net.corda.core.internal.createDirectories
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
import net.corda.nodeapi.internal.crypto.*
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
|
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
||||||
|
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import javax.security.auth.x500.X500Principal
|
import javax.security.auth.x500.X500Principal
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
@ -103,7 +104,7 @@ fun generateSigningKeyPairs(keystoreFile: Path, rootStoreFile: Path, rootKeystor
|
|||||||
}
|
}
|
||||||
|
|
||||||
storeCertIfAbsent(
|
storeCertIfAbsent(
|
||||||
DEFAULT_CSR_CERTIFICATE_NAME,
|
X509Utilities.CORDA_INTERMEDIATE_CA,
|
||||||
CertificateType.INTERMEDIATE_CA,
|
CertificateType.INTERMEDIATE_CA,
|
||||||
X500Principal("CN=Corda Doorman CA,$CORDA_X500_BASE"),
|
X500Principal("CN=Corda Doorman CA,$CORDA_X500_BASE"),
|
||||||
X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||||
|
@ -18,7 +18,6 @@ import com.r3.corda.networkmanage.hsm.persistence.DBSignedCertificateRequestStor
|
|||||||
import com.r3.corda.networkmanage.hsm.signer.HsmCsrSigner
|
import com.r3.corda.networkmanage.hsm.signer.HsmCsrSigner
|
||||||
import com.r3.corda.networkmanage.hsm.signer.HsmSigner
|
import com.r3.corda.networkmanage.hsm.signer.HsmSigner
|
||||||
import com.r3.corda.networkmanage.hsm.utils.mapCryptoServerException
|
import com.r3.corda.networkmanage.hsm.utils.mapCryptoServerException
|
||||||
import net.corda.core.utilities.minutes
|
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||||
import java.security.Security
|
import java.security.Security
|
||||||
@ -74,10 +73,9 @@ fun run(parameters: Parameters) {
|
|||||||
val sign: (List<ApprovedCertificateRequestData>) -> Unit = {
|
val sign: (List<ApprovedCertificateRequestData>) -> Unit = {
|
||||||
val signer = HsmCsrSigner(
|
val signer = HsmCsrSigner(
|
||||||
csrStorage,
|
csrStorage,
|
||||||
csrCertificateName,
|
loadRootKeyStore(),
|
||||||
csrCertCrlDistPoint,
|
csrCertCrlDistPoint,
|
||||||
csrCertCrlIssuer,
|
csrCertCrlIssuer,
|
||||||
rootCertificateName,
|
|
||||||
validDays,
|
validDays,
|
||||||
Authenticator(
|
Authenticator(
|
||||||
authMode,
|
authMode,
|
||||||
@ -85,8 +83,7 @@ fun run(parameters: Parameters) {
|
|||||||
authKeyFilePath,
|
authKeyFilePath,
|
||||||
authKeyFilePassword,
|
authKeyFilePassword,
|
||||||
signAuthThreshold,
|
signAuthThreshold,
|
||||||
provider = createProvider(doormanKeyGroup),
|
provider = createProvider(doormanKeyGroup)))
|
||||||
rootProvider = createProvider(rootKeyGroup)))
|
|
||||||
signer.sign(it)
|
signer.sign(it)
|
||||||
}
|
}
|
||||||
Menu().withExceptionHandler(::processError).addItem("1", "Sign all approved and unsigned CSRs", {
|
Menu().withExceptionHandler(::processError).addItem("1", "Sign all approved and unsigned CSRs", {
|
||||||
|
@ -17,18 +17,16 @@ class Authenticator(private val mode: AuthMode = AuthMode.PASSWORD,
|
|||||||
private val authKeyFilePass: String? = null,
|
private val authKeyFilePass: String? = null,
|
||||||
private val authStrengthThreshold: Int = 2,
|
private val authStrengthThreshold: Int = 2,
|
||||||
inputReader: InputReader = ConsoleInputReader(),
|
inputReader: InputReader = ConsoleInputReader(),
|
||||||
private val provider: CryptoServerProvider,
|
private val provider: CryptoServerProvider) : InputReader by inputReader {
|
||||||
private val rootProvider: CryptoServerProvider? = null) : InputReader by inputReader {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interactively (using console) authenticates a user against the HSM. Once authentication is successful the
|
* Interactively (using console) authenticates a user against the HSM. Once authentication is successful the
|
||||||
* [block] is executed.
|
* [block] is executed.
|
||||||
* @param block to be executed once the authentication process succeeds. The block should take 3 parameters:
|
* @param block to be executed once the authentication process succeeds. The block should take 3 parameters:
|
||||||
* 1) [CryptoServerProvider] instance of the certificate provider
|
* 1) [CryptoServerProvider] instance of the certificate provider
|
||||||
* 2) [CryptoServerProvider] instance of the root certificate provider
|
|
||||||
* 2) List of strings that corresponds to user names authenticated against the HSM.
|
* 2) List of strings that corresponds to user names authenticated against the HSM.
|
||||||
*/
|
*/
|
||||||
fun <T : Any> connectAndAuthenticate(block: (CryptoServerProvider, CryptoServerProvider?, List<String>) -> T): T {
|
fun <T : Any> connectAndAuthenticate(block: (CryptoServerProvider, List<String>) -> T): T {
|
||||||
return try {
|
return try {
|
||||||
val authenticated = mutableListOf<String>()
|
val authenticated = mutableListOf<String>()
|
||||||
loop@ while (true) {
|
loop@ while (true) {
|
||||||
@ -49,10 +47,6 @@ class Authenticator(private val mode: AuthMode = AuthMode.PASSWORD,
|
|||||||
println("Authenticating using card reader")
|
println("Authenticating using card reader")
|
||||||
println("Accessing the certificate key group data...")
|
println("Accessing the certificate key group data...")
|
||||||
provider.loginSign(user, ":cs2:cyb:USB0", null)
|
provider.loginSign(user, ":cs2:cyb:USB0", null)
|
||||||
if (rootProvider != null) {
|
|
||||||
println("Accessing the root certificate key group data...")
|
|
||||||
rootProvider.loginSign(user, ":cs2:cyb:USB0", null)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
AuthMode.KEY_FILE -> {
|
AuthMode.KEY_FILE -> {
|
||||||
println("Authenticating using preconfigured key file $authKeyFilePath")
|
println("Authenticating using preconfigured key file $authKeyFilePath")
|
||||||
@ -69,10 +63,6 @@ class Authenticator(private val mode: AuthMode = AuthMode.PASSWORD,
|
|||||||
}
|
}
|
||||||
println("Accessing the certificate key group data...")
|
println("Accessing the certificate key group data...")
|
||||||
provider.loginSign(user, authKeyFilePath.toString(), password)
|
provider.loginSign(user, authKeyFilePath.toString(), password)
|
||||||
if (rootProvider != null) {
|
|
||||||
println("Accessing the root certificate key group data...")
|
|
||||||
rootProvider.loginSign(user, authKeyFilePath.toString(), password)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
AuthMode.PASSWORD -> {
|
AuthMode.PASSWORD -> {
|
||||||
println("Authenticating using password")
|
println("Authenticating using password")
|
||||||
@ -83,10 +73,6 @@ class Authenticator(private val mode: AuthMode = AuthMode.PASSWORD,
|
|||||||
}
|
}
|
||||||
println("Accessing the certificate key group data...")
|
println("Accessing the certificate key group data...")
|
||||||
provider.loginPassword(user, password)
|
provider.loginPassword(user, password)
|
||||||
if (rootProvider != null) {
|
|
||||||
println("Accessing the root certificate key group data...")
|
|
||||||
rootProvider.loginPassword(user, password)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
authenticated.add(user!!)
|
authenticated.add(user!!)
|
||||||
@ -99,7 +85,7 @@ class Authenticator(private val mode: AuthMode = AuthMode.PASSWORD,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!authenticated.isEmpty()) {
|
if (!authenticated.isEmpty()) {
|
||||||
block(provider, rootProvider, authenticated)
|
block(provider, authenticated)
|
||||||
} else {
|
} else {
|
||||||
throw AuthenticationException()
|
throw AuthenticationException()
|
||||||
}
|
}
|
||||||
@ -113,8 +99,8 @@ class Authenticator(private val mode: AuthMode = AuthMode.PASSWORD,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
|
|
||||||
|
/*
|
||||||
* Configuration class for [CryptoServerProvider]
|
* Configuration class for [CryptoServerProvider]
|
||||||
*/
|
*/
|
||||||
data class CryptoServerProviderConfig(
|
data class CryptoServerProviderConfig(
|
||||||
|
@ -8,7 +8,7 @@ import net.corda.core.internal.div
|
|||||||
import net.corda.core.internal.isRegularFile
|
import net.corda.core.internal.isRegularFile
|
||||||
import net.corda.core.utilities.minutes
|
import net.corda.core.utilities.minutes
|
||||||
import net.corda.nodeapi.internal.config.parseAs
|
import net.corda.nodeapi.internal.config.parseAs
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
||||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
@ -21,15 +21,14 @@ data class Parameters(val dataSourceProperties: Properties,
|
|||||||
val databaseConfig: DatabaseConfig = DatabaseConfig(),
|
val databaseConfig: DatabaseConfig = DatabaseConfig(),
|
||||||
val device: String = DEFAULT_DEVICE,
|
val device: String = DEFAULT_DEVICE,
|
||||||
// TODO this needs cleaning up after the config-file-only support is implemented
|
// TODO this needs cleaning up after the config-file-only support is implemented
|
||||||
val rootKeyGroup: String,
|
val rootKeyStoreFile: Path,
|
||||||
val doormanKeyGroup:String,
|
val rootKeyStorePassword: String,
|
||||||
|
val doormanKeyGroup: String,
|
||||||
val networkMapKeyGroup: String,
|
val networkMapKeyGroup: String,
|
||||||
val keySpecifier: Int = DEFAULT_KEY_SPECIFIER,
|
val keySpecifier: Int = DEFAULT_KEY_SPECIFIER,
|
||||||
val csrCertificateName: String = DEFAULT_CSR_CERTIFICATE_NAME,
|
|
||||||
val csrCertCrlDistPoint: String,
|
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",
|
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.
|
// if null parent CA is is considered as an issuer.
|
||||||
val rootCertificateName: String = DEFAULT_ROOT_CERTIFICATE_NAME,
|
|
||||||
val validDays: Int,
|
val validDays: Int,
|
||||||
val signAuthThreshold: Int = DEFAULT_SIGN_AUTH_THRESHOLD,
|
val signAuthThreshold: Int = DEFAULT_SIGN_AUTH_THRESHOLD,
|
||||||
val keyGenAuthThreshold: Int = DEFAULT_KEY_GEN_AUTH_THRESHOLD,
|
val keyGenAuthThreshold: Int = DEFAULT_KEY_GEN_AUTH_THRESHOLD,
|
||||||
@ -44,8 +43,6 @@ data class Parameters(val dataSourceProperties: Properties,
|
|||||||
val DEFAULT_AUTH_MODE = AuthMode.PASSWORD
|
val DEFAULT_AUTH_MODE = AuthMode.PASSWORD
|
||||||
val DEFAULT_SIGN_AUTH_THRESHOLD = 2
|
val DEFAULT_SIGN_AUTH_THRESHOLD = 2
|
||||||
val DEFAULT_KEY_GEN_AUTH_THRESHOLD = 2
|
val DEFAULT_KEY_GEN_AUTH_THRESHOLD = 2
|
||||||
val DEFAULT_CSR_CERTIFICATE_NAME = X509Utilities.CORDA_INTERMEDIATE_CA
|
|
||||||
val DEFAULT_ROOT_CERTIFICATE_NAME = X509Utilities.CORDA_ROOT_CA
|
|
||||||
val DEFAULT_KEY_SPECIFIER = 1
|
val DEFAULT_KEY_SPECIFIER = 1
|
||||||
val DEFAULT_KEY_FILE_PATH: Path? = null //Paths.get("/Users/michalkit/WinDev1706Eval/Shared/TEST4.key")
|
val DEFAULT_KEY_FILE_PATH: Path? = null //Paths.get("/Users/michalkit/WinDev1706Eval/Shared/TEST4.key")
|
||||||
val DEFAULT_KEY_FILE_PASSWORD: String? = null
|
val DEFAULT_KEY_FILE_PASSWORD: String? = null
|
||||||
@ -53,6 +50,10 @@ data class Parameters(val dataSourceProperties: Properties,
|
|||||||
val DEFAULT_SIGN_INTERVAL = 1.minutes.toMillis()
|
val DEFAULT_SIGN_INTERVAL = 1.minutes.toMillis()
|
||||||
val DEFAULT_CSR_CERT_CRL_ISSUER: String? = null
|
val DEFAULT_CSR_CERT_CRL_ISSUER: String? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun loadRootKeyStore(createNew: Boolean = false): X509KeyStore {
|
||||||
|
return X509KeyStore.fromFile(rootKeyStoreFile, rootKeyStorePassword, createNew)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,18 +7,17 @@ import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.createClientCertifi
|
|||||||
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.getAndInitializeKeyStore
|
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.getAndInitializeKeyStore
|
||||||
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.retrieveCertAndKeyPair
|
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.retrieveCertAndKeyPair
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
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
|
||||||
import net.corda.nodeapi.internal.crypto.getX509Certificate
|
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates certificate signing logic
|
* Encapsulates certificate signing logic
|
||||||
*/
|
*/
|
||||||
class HsmCsrSigner(private val storage: SignedCertificateRequestStorage,
|
class HsmCsrSigner(private val storage: SignedCertificateRequestStorage,
|
||||||
private val intermediateCertAlias: String,
|
private val rootKeyStore: X509KeyStore,
|
||||||
private val csrCertCrlDistPoint: String,
|
private val csrCertCrlDistPoint: String,
|
||||||
private val csrCertCrlIssuer: String?,
|
private val csrCertCrlIssuer: String?,
|
||||||
private val rootCertAlias: String,
|
|
||||||
private val validDays: Int,
|
private val validDays: Int,
|
||||||
private val authenticator: Authenticator) : CertificateSigningRequestSigner {
|
private val authenticator: Authenticator) : CertificateSigningRequestSigner {
|
||||||
|
|
||||||
@ -33,11 +32,12 @@ class HsmCsrSigner(private val storage: SignedCertificateRequestStorage,
|
|||||||
* @param toSign list of approved certificates to be signed
|
* @param toSign list of approved certificates to be signed
|
||||||
*/
|
*/
|
||||||
override fun sign(toSign: List<ApprovedCertificateRequestData>) {
|
override fun sign(toSign: List<ApprovedCertificateRequestData>) {
|
||||||
authenticator.connectAndAuthenticate { provider, rootProvider, signers ->
|
authenticator.connectAndAuthenticate { provider, signers ->
|
||||||
val rootKeyStore = getAndInitializeKeyStore(rootProvider!!)
|
// This should be changed once we allow for more certificates in the chain. Preferably we should use
|
||||||
val rootCert = rootKeyStore.getX509Certificate(rootCertAlias)
|
// keyStore.getCertificateChain(String) and assume entire chain is stored in the HSM (depending on the support).
|
||||||
|
val rootCert = rootKeyStore.getCertificate(X509Utilities.CORDA_ROOT_CA)
|
||||||
val keyStore = getAndInitializeKeyStore(provider)
|
val keyStore = getAndInitializeKeyStore(provider)
|
||||||
val doormanCertAndKey = retrieveCertAndKeyPair(intermediateCertAlias, keyStore)
|
val doormanCertAndKey = retrieveCertAndKeyPair(X509Utilities.CORDA_INTERMEDIATE_CA, keyStore)
|
||||||
toSign.forEach {
|
toSign.forEach {
|
||||||
val nodeCaCert = createClientCertificate(
|
val nodeCaCert = createClientCertificate(
|
||||||
CertificateType.NODE_CA,
|
CertificateType.NODE_CA,
|
||||||
|
@ -19,7 +19,7 @@ class HsmSigner(private val authenticator: Authenticator) : Signer {
|
|||||||
* Signs given data using [CryptoServerJCE.CryptoServerProvider], which connects to the underlying HSM.
|
* Signs given data using [CryptoServerJCE.CryptoServerProvider], which connects to the underlying HSM.
|
||||||
*/
|
*/
|
||||||
override fun signBytes(data: ByteArray): DigitalSignatureWithCert {
|
override fun signBytes(data: ByteArray): DigitalSignatureWithCert {
|
||||||
return authenticator.connectAndAuthenticate { provider, _, _ ->
|
return authenticator.connectAndAuthenticate { provider, _ ->
|
||||||
val keyStore = getAndInitializeKeyStore(provider)
|
val keyStore = getAndInitializeKeyStore(provider)
|
||||||
val certificate = keyStore.getX509Certificate(CORDA_NETWORK_MAP)
|
val certificate = keyStore.getX509Certificate(CORDA_NETWORK_MAP)
|
||||||
// Don't worry this is not a real private key but a pointer to one that resides in the HSM. It only works
|
// Don't worry this is not a real private key but a pointer to one that resides in the HSM. It only works
|
||||||
|
@ -28,7 +28,7 @@ class AuthenticatorTest : TestBase() {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
assertFailsWith<AuthenticationException> {
|
assertFailsWith<AuthenticationException> {
|
||||||
Authenticator(provider = provider, inputReader = inputReader).connectAndAuthenticate { _, _, _ -> }
|
Authenticator(provider = provider, inputReader = inputReader).connectAndAuthenticate { _, _ -> }
|
||||||
}
|
}
|
||||||
|
|
||||||
//then
|
//then
|
||||||
@ -47,7 +47,7 @@ class AuthenticatorTest : TestBase() {
|
|||||||
var executed = false
|
var executed = false
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Authenticator(provider = provider, inputReader = inputReader).connectAndAuthenticate { _, _, _ -> executed = true }
|
Authenticator(provider = provider, inputReader = inputReader).connectAndAuthenticate { _, _ -> executed = true }
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(provider).loginPassword(username, password)
|
verify(provider).loginPassword(username, password)
|
||||||
@ -64,7 +64,7 @@ class AuthenticatorTest : TestBase() {
|
|||||||
var executed = false
|
var executed = false
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Authenticator(provider = provider, inputReader = inputReader, mode = AuthMode.CARD_READER).connectAndAuthenticate { _, _, _ -> executed = true }
|
Authenticator(provider = provider, inputReader = inputReader, mode = AuthMode.CARD_READER).connectAndAuthenticate { _, _ -> executed = true }
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(provider).loginSign(username, ":cs2:cyb:USB0", null)
|
verify(provider).loginSign(username, ":cs2:cyb:USB0", null)
|
||||||
@ -83,7 +83,7 @@ class AuthenticatorTest : TestBase() {
|
|||||||
var executed = false
|
var executed = false
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Authenticator(provider = provider, inputReader = inputReader).connectAndAuthenticate { _, _, _ -> executed = true }
|
Authenticator(provider = provider, inputReader = inputReader).connectAndAuthenticate { _, _ -> executed = true }
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(provider, times(3)).loginPassword(username, password)
|
verify(provider, times(3)).loginPassword(username, password)
|
||||||
|
Reference in New Issue
Block a user