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:
Michal Kit
2018-02-05 12:39:57 +00:00
committed by GitHub
parent b092b6b547
commit 3baa15960f
14 changed files with 83 additions and 85 deletions

View File

@ -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.

View File

@ -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

View File

@ -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)
} }
} }

View File

@ -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())

View File

@ -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))

View File

@ -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

View File

@ -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)
} }

View File

@ -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)

View File

@ -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", {

View File

@ -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(

View File

@ -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 rootKeyStorePassword: String,
val doormanKeyGroup: 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)
}
} }
/** /**

View File

@ -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,

View File

@ -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

View File

@ -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)