mirror of
https://github.com/corda/corda.git
synced 2024-12-27 08:22:35 +00:00
Addressing multiple key groups. Removing redundant config parameters for private key passwords (#409)
This commit is contained in:
parent
5f1590d97f
commit
83ea4611ca
@ -46,6 +46,8 @@ Certificate Configuration
|
|||||||
:certificateType: Type of the certificate to be created. Allowed values are:
|
:certificateType: Type of the certificate to be created. Allowed values are:
|
||||||
ROOT_CA, INTERMEDIATE_CA, NETWORK_MAP.
|
ROOT_CA, INTERMEDIATE_CA, NETWORK_MAP.
|
||||||
|
|
||||||
|
:rootKeyGroup: This is an HSM specific parameter that corresponds to key name spacing for the root key. It is ignored if the certificateType value is ROOT_CA. See Utimaco documentation for more details.
|
||||||
|
|
||||||
:subject: X500Name formatted string to be used as the certificate public key subject.
|
:subject: X500Name formatted string to be used as the certificate public key subject.
|
||||||
|
|
||||||
:validDays: Days number for certificate validity.
|
:validDays: Days number for certificate validity.
|
||||||
@ -64,7 +66,7 @@ Certificate Configuration
|
|||||||
|
|
||||||
:keySpecifier: This is an HSM specific parameter that corresponds to key name spacing. See Utimaco documentation for more details.
|
:keySpecifier: This is an HSM specific parameter that corresponds to key name spacing. See Utimaco documentation for more details.
|
||||||
|
|
||||||
:keyGroup: This is an HSM specific parameter that corresponds to key name spacing. See Utimaco documentation for more details.
|
:keyGroup: This is an HSM specific parameter that corresponds to key name spacing for the generated key. See Utimaco documentation for more details.
|
||||||
|
|
||||||
|
|
||||||
User Authentication Configuration
|
User Authentication Configuration
|
||||||
@ -78,6 +80,6 @@ Allowed parameters are:
|
|||||||
CARD_READER - Smart card reader authentication
|
CARD_READER - Smart card reader authentication
|
||||||
KEY_FILE - Key file based authentication.
|
KEY_FILE - Key file based authentication.
|
||||||
|
|
||||||
:authToken: Depending on the authMode it is either user's password or path to the authentication key file.
|
:authToken: Depending on the authMode it is either user's password or path to the authentication key file. In case of the CARD_READER authMode value, this can be omitted.
|
||||||
|
|
||||||
:keyFilePassword: Only relevant, if authMode == KEY_FILE. It is the key file password.
|
:keyFilePassword: Only relevant, if authMode == KEY_FILE. It is the key file password.
|
@ -28,7 +28,11 @@ 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"
|
||||||
|
|
||||||
:keyGroup: HSM key group. This parameter is vendor specific (see Utimaco docs).
|
:rootKeyGroup: HSM key group for the root 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).
|
||||||
|
|
||||||
|
:doormanKeyGroup: HSM key group for the doorman certificate key. This parameter is vendor specific (see Utimaco docs).
|
||||||
|
|
||||||
:keySpecifier: HSM key specifier. This parameter is vendor specific (see Utimaco docs). Default value: 1.
|
:keySpecifier: HSM key specifier. This parameter is vendor specific (see Utimaco docs). Default value: 1.
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ trustStoreDirectory = "."
|
|||||||
trustStorePassword = "trustpass"
|
trustStorePassword = "trustpass"
|
||||||
|
|
||||||
certConfig {
|
certConfig {
|
||||||
subject = "CN=Corda Root, O=R3Cev, L=London, C=GB"
|
subject = "CN=Corda Root, O=R3 HoldCo LLC, OU=Corda, L=New York, C=US"
|
||||||
certificateType = ROOT_CA
|
certificateType = ROOT_CA
|
||||||
validDays = 3650
|
validDays = 3650
|
||||||
keyOverride = 0
|
keyOverride = 0
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
basedir = "."
|
basedir = "."
|
||||||
device = "3001@127.0.0.1"
|
device = "3001@192.168.0.1"
|
||||||
keyGroup = "DEV.DOORMAN"
|
|
||||||
keySpecifier = -1
|
keySpecifier = -1
|
||||||
authMode = PASSWORD
|
authMode = PASSWORD
|
||||||
rootCertificateName = "corda_root_ca"
|
rootCertificateName = "corda_root_ca"
|
||||||
rootPrivateKeyPassword = "Password"
|
|
||||||
csrPrivateKeyPassword = "Password"
|
|
||||||
csrCertificateName = "intermediate_ca"
|
csrCertificateName = "intermediate_ca"
|
||||||
csrCertCrlDistPoint = "http://test.com/revoked.crl"
|
csrCertCrlDistPoint = "http://test.com/revoked.crl"
|
||||||
networkMapCertificateName = "intermediate_ca"
|
networkMapCertificateName = "intermediate_ca"
|
||||||
networkMapPrivateKeyPassword = "Password"
|
rootKeyGroup = "DEV.CORDACONNECT.ROOT"
|
||||||
|
doormanKeyGroup = "DEV.CORDACONNECT.OPS.CERT"
|
||||||
|
networkMapKeyGroup = "DEV.CORDACONNECT.OPS.NETMAP"
|
||||||
validDays = 3650
|
validDays = 3650
|
||||||
signAuthThreshold = 2
|
signAuthThreshold = 2
|
||||||
keyGenAuthThreshold = 2
|
keyGenAuthThreshold = 2
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.r3.corda.networkmanage.hsm
|
||||||
|
|
||||||
|
import com.r3.corda.networkmanage.hsm.authentication.Authenticator
|
||||||
|
import com.r3.corda.networkmanage.hsm.authentication.createProvider
|
||||||
|
import org.junit.Test
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class HsmAuthenticatorTest : HsmCertificateTest() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Authenticator executes the block once user is successfully authenticated`() {
|
||||||
|
// given
|
||||||
|
val userInput = givenHsmUserAuthenticationInput()
|
||||||
|
val authenticator = Authenticator(provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.rootKeyGroup), inputReader = userInput)
|
||||||
|
val executed = AtomicBoolean(false)
|
||||||
|
|
||||||
|
// when
|
||||||
|
authenticator.connectAndAuthenticate { _, _, _ -> executed.set(true) }
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(executed.get())
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
package com.r3.corda.networkmanage.hsm
|
||||||
|
|
||||||
|
import com.nhaarman.mockito_kotlin.any
|
||||||
|
import com.nhaarman.mockito_kotlin.mock
|
||||||
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
|
import com.r3.corda.networkmanage.HsmSimulator
|
||||||
|
import com.r3.corda.networkmanage.hsm.authentication.CryptoServerProviderConfig
|
||||||
|
import com.r3.corda.networkmanage.hsm.authentication.InputReader
|
||||||
|
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
|
||||||
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.rules.TemporaryFolder
|
||||||
|
|
||||||
|
abstract class HsmCertificateTest {
|
||||||
|
companion object {
|
||||||
|
val ROOT_CERT_KEY_GROUP = "DEV.CORDACONNECT.ROOT"
|
||||||
|
val NETWORK_MAP_CERT_KEY_GROUP = "DEV.CORDACONNECT.OPS.NETMAP"
|
||||||
|
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"
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
@JvmField
|
||||||
|
val tempFolder = TemporaryFolder()
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
@JvmField
|
||||||
|
val hsmSimulator: HsmSimulator = HsmSimulator()
|
||||||
|
|
||||||
|
protected val rootCertParameters: GeneratorParameters by lazy {
|
||||||
|
GeneratorParameters(
|
||||||
|
hsmHost = hsmSimulator.host,
|
||||||
|
hsmPort = hsmSimulator.port,
|
||||||
|
trustStoreDirectory = tempFolder.root.toPath(),
|
||||||
|
trustStorePassword = "",
|
||||||
|
userConfigs = listOf(UserAuthenticationParameters(
|
||||||
|
username = "INTEGRATION_TEST",
|
||||||
|
authMode = AuthMode.PASSWORD,
|
||||||
|
authToken = "INTEGRATION_TEST",
|
||||||
|
keyFilePassword = null
|
||||||
|
)),
|
||||||
|
certConfig = CertificateConfiguration(
|
||||||
|
keySpecifier = 1,
|
||||||
|
keyGroup = ROOT_CERT_KEY_GROUP,
|
||||||
|
storeKeysExternal = false,
|
||||||
|
rootKeyGroup = null,
|
||||||
|
subject = ROOT_CERT_SUBJECT,
|
||||||
|
validDays = 3650,
|
||||||
|
keyCurve = "NIST-P256",
|
||||||
|
certificateType = CertificateType.ROOT_CA,
|
||||||
|
keyExport = 0,
|
||||||
|
keyGenMechanism = 4,
|
||||||
|
keyOverride = 0,
|
||||||
|
crlIssuer = null,
|
||||||
|
crlDistributionUrl = null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected val providerConfig: CryptoServerProviderConfig by lazy {
|
||||||
|
CryptoServerProviderConfig(
|
||||||
|
Device = "${rootCertParameters.hsmPort}@${rootCertParameters.hsmHost}",
|
||||||
|
KeySpecifier = rootCertParameters.certConfig.keySpecifier,
|
||||||
|
KeyGroup = rootCertParameters.certConfig.keyGroup,
|
||||||
|
StoreKeysExternal = rootCertParameters.certConfig.storeKeysExternal)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected val hsmSigningServiceConfig = Parameters(
|
||||||
|
dataSourceProperties = mock(),
|
||||||
|
device = "${hsmSimulator.port}@${hsmSimulator.host}",
|
||||||
|
keySpecifier = 1,
|
||||||
|
rootKeyGroup = ROOT_CERT_KEY_GROUP,
|
||||||
|
doormanKeyGroup = DOORMAN_CERT_KEY_GROUP,
|
||||||
|
networkMapKeyGroup = NETWORK_MAP_CERT_KEY_GROUP,
|
||||||
|
validDays = 3650,
|
||||||
|
csrCertCrlDistPoint = "http://test.com/revoked.crl"
|
||||||
|
)
|
||||||
|
|
||||||
|
protected fun givenHsmUserAuthenticationInput(): InputReader {
|
||||||
|
val inputReader = mock<InputReader>()
|
||||||
|
whenever(inputReader.readLine()).thenReturn(hsmSimulator.cryptoUserCredentials().username)
|
||||||
|
whenever(inputReader.readPassword(any())).thenReturn(hsmSimulator.cryptoUserCredentials().password)
|
||||||
|
return inputReader
|
||||||
|
}
|
||||||
|
}
|
@ -1,111 +1,82 @@
|
|||||||
package com.r3.corda.networkmanage.hsm
|
package com.r3.corda.networkmanage.hsm
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.HsmSimulator
|
import com.nhaarman.mockito_kotlin.any
|
||||||
|
import com.nhaarman.mockito_kotlin.mock
|
||||||
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
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.authentication.CryptoServerProviderConfig
|
import com.r3.corda.networkmanage.hsm.authentication.InputReader
|
||||||
import com.r3.corda.networkmanage.hsm.generator.*
|
import com.r3.corda.networkmanage.hsm.generator.AutoAuthenticator
|
||||||
|
import com.r3.corda.networkmanage.hsm.generator.run
|
||||||
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities
|
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities
|
||||||
|
import net.corda.core.identity.CordaX500Name
|
||||||
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_INTERMEDIATE_CA
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
|
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
|
||||||
import org.junit.Rule
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.rules.TemporaryFolder
|
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertNotNull
|
import kotlin.test.assertNotNull
|
||||||
|
|
||||||
class HsmKeyGenerationTest {
|
class HsmKeyGenerationTest : HsmCertificateTest() {
|
||||||
|
|
||||||
@Rule
|
private lateinit var inputReader: InputReader
|
||||||
@JvmField
|
|
||||||
val tempFolder = TemporaryFolder()
|
|
||||||
|
|
||||||
@Rule
|
@Before
|
||||||
@JvmField
|
fun setUp() {
|
||||||
val hsmSimulator: HsmSimulator = HsmSimulator()
|
inputReader = mock()
|
||||||
|
whenever(inputReader.readLine()).thenReturn(hsmSimulator.cryptoUserCredentials().username)
|
||||||
private val rootCertParameters: GeneratorParameters by lazy {
|
whenever(inputReader.readPassword(any())).thenReturn(hsmSimulator.cryptoUserCredentials().password)
|
||||||
GeneratorParameters(
|
|
||||||
hsmHost = hsmSimulator.host,
|
|
||||||
hsmPort = hsmSimulator.port,
|
|
||||||
trustStoreDirectory = tempFolder.root.toPath(),
|
|
||||||
trustStorePassword = "",
|
|
||||||
userConfigs = listOf(UserAuthenticationParameters(
|
|
||||||
username = "INTEGRATION_TEST",
|
|
||||||
authMode = AuthMode.PASSWORD,
|
|
||||||
authToken = "INTEGRATION_TEST",
|
|
||||||
keyFilePassword = null
|
|
||||||
)),
|
|
||||||
certConfig = CertificateConfiguration(
|
|
||||||
keySpecifier = 1,
|
|
||||||
keyGroup = "DEV.DOORMAN",
|
|
||||||
storeKeysExternal = false,
|
|
||||||
subject = "CN=Corda Root, O=R3Cev, L=London, C=GB",
|
|
||||||
validDays = 3650,
|
|
||||||
keyCurve = "NIST-P256",
|
|
||||||
certificateType = CertificateType.ROOT_CA,
|
|
||||||
keyExport = 0,
|
|
||||||
keyGenMechanism = 4,
|
|
||||||
keyOverride = 0,
|
|
||||||
crlIssuer = null,
|
|
||||||
crlDistributionUrl = null
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val providerConfig: CryptoServerProviderConfig by lazy {
|
|
||||||
CryptoServerProviderConfig(
|
|
||||||
Device = "${rootCertParameters.hsmPort}@${rootCertParameters.hsmHost}",
|
|
||||||
KeySpecifier = rootCertParameters.certConfig.keySpecifier,
|
|
||||||
KeyGroup = rootCertParameters.certConfig.keyGroup,
|
|
||||||
StoreKeysExternal = rootCertParameters.certConfig.storeKeysExternal)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Authenticator executes the block once user is successfully authenticated`() {
|
fun `Root and network map certificates have different namespace`() {
|
||||||
// given
|
|
||||||
val authenticator = AutoAuthenticator(providerConfig, rootCertParameters.userConfigs)
|
|
||||||
val rootCertGenerator = KeyCertificateGenerator(rootCertParameters)
|
|
||||||
// when root cert is created
|
// when root cert is created
|
||||||
authenticator.connectAndAuthenticate { provider ->
|
run(rootCertParameters)
|
||||||
rootCertGenerator.generate(provider)
|
// when network map cert is created
|
||||||
// then
|
run(rootCertParameters.copy(
|
||||||
|
certConfig = rootCertParameters.certConfig.copy(
|
||||||
|
keyGroup = NETWORK_MAP_CERT_KEY_GROUP,
|
||||||
|
rootKeyGroup = ROOT_CERT_KEY_GROUP,
|
||||||
|
certificateType = CertificateType.NETWORK_MAP,
|
||||||
|
subject = NETWORK_MAP_CERT_SUBJECT
|
||||||
|
)
|
||||||
|
))
|
||||||
|
// when doorman cert is created
|
||||||
|
run(rootCertParameters.copy(
|
||||||
|
certConfig = rootCertParameters.certConfig.copy(
|
||||||
|
keyGroup = DOORMAN_CERT_KEY_GROUP,
|
||||||
|
rootKeyGroup = ROOT_CERT_KEY_GROUP,
|
||||||
|
certificateType = CertificateType.INTERMEDIATE_CA,
|
||||||
|
subject = DOORMAN_CERT_SUBJECT
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
// then root cert is persisted in the HSM
|
||||||
|
AutoAuthenticator(providerConfig, rootCertParameters.userConfigs).connectAndAuthenticate { provider ->
|
||||||
val keyStore = HsmX509Utilities.getAndInitializeKeyStore(provider)
|
val keyStore = HsmX509Utilities.getAndInitializeKeyStore(provider)
|
||||||
val rootCert = keyStore.getCertificate(CORDA_ROOT_CA) as X509Certificate
|
val rootCert = keyStore.getCertificate(CORDA_ROOT_CA) as X509Certificate
|
||||||
assertEquals(rootCert.issuerX500Principal, rootCert.subjectX500Principal)
|
assertEquals(rootCert.issuerX500Principal, rootCert.subjectX500Principal)
|
||||||
}
|
}
|
||||||
// when network map cert is created
|
|
||||||
val networkMapCertGenerator = KeyCertificateGenerator(rootCertParameters.copy(
|
// then network map cert is persisted in the HSM
|
||||||
certConfig = rootCertParameters.certConfig.copy(
|
|
||||||
certificateType = CertificateType.NETWORK_MAP,
|
AutoAuthenticator(providerConfig.copy(KeyGroup = NETWORK_MAP_CERT_KEY_GROUP), rootCertParameters.userConfigs)
|
||||||
subject = "CN=Corda NM, O=R3Cev, L=London, C=GB"
|
.connectAndAuthenticate { provider ->
|
||||||
)
|
|
||||||
))
|
|
||||||
authenticator.connectAndAuthenticate { provider ->
|
|
||||||
networkMapCertGenerator.generate(provider)
|
|
||||||
// then
|
|
||||||
val keyStore = HsmX509Utilities.getAndInitializeKeyStore(provider)
|
val keyStore = HsmX509Utilities.getAndInitializeKeyStore(provider)
|
||||||
val rootCert = keyStore.getCertificate(CORDA_ROOT_CA) as X509Certificate
|
|
||||||
val networkMapCert = keyStore.getCertificate(CORDA_NETWORK_MAP) as X509Certificate
|
val networkMapCert = keyStore.getCertificate(CORDA_NETWORK_MAP) as X509Certificate
|
||||||
assertNotNull(networkMapCert)
|
assertNotNull(networkMapCert)
|
||||||
assertEquals(rootCert.subjectX500Principal, networkMapCert.issuerX500Principal)
|
assertEquals(CordaX500Name.parse(ROOT_CERT_SUBJECT).x500Principal, networkMapCert.issuerX500Principal)
|
||||||
}
|
}
|
||||||
// when csr cert is created
|
|
||||||
val csrCertGenerator = KeyCertificateGenerator(rootCertParameters.copy(
|
// then doorman cert is persisted in the HSM
|
||||||
certConfig = rootCertParameters.certConfig.copy(
|
|
||||||
certificateType = CertificateType.INTERMEDIATE_CA,
|
AutoAuthenticator(providerConfig.copy(KeyGroup = DOORMAN_CERT_KEY_GROUP), rootCertParameters.userConfigs)
|
||||||
subject = "CN=Corda CSR, O=R3Cev, L=London, C=GB"
|
.connectAndAuthenticate { provider ->
|
||||||
)
|
|
||||||
))
|
|
||||||
authenticator.connectAndAuthenticate { provider ->
|
|
||||||
csrCertGenerator.generate(provider)
|
|
||||||
// then
|
|
||||||
val keyStore = HsmX509Utilities.getAndInitializeKeyStore(provider)
|
val keyStore = HsmX509Utilities.getAndInitializeKeyStore(provider)
|
||||||
val rootCert = keyStore.getCertificate(CORDA_ROOT_CA) as X509Certificate
|
val networkMapCert = keyStore.getCertificate(CORDA_INTERMEDIATE_CA) as X509Certificate
|
||||||
val csrCert = keyStore.getCertificate(CORDA_INTERMEDIATE_CA) as X509Certificate
|
assertNotNull(networkMapCert)
|
||||||
assertNotNull(csrCert)
|
assertEquals(CordaX500Name.parse(ROOT_CERT_SUBJECT).x500Principal, networkMapCert.issuerX500Principal)
|
||||||
assertEquals(rootCert.subjectX500Principal, csrCert.issuerX500Principal)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
package com.r3.corda.networkmanage.hsm
|
||||||
|
|
||||||
|
import com.nhaarman.mockito_kotlin.mock
|
||||||
|
import com.r3.corda.networkmanage.hsm.authentication.Authenticator
|
||||||
|
import com.r3.corda.networkmanage.hsm.authentication.createProvider
|
||||||
|
import com.r3.corda.networkmanage.hsm.generator.run
|
||||||
|
import com.r3.corda.networkmanage.hsm.persistence.ApprovedCertificateRequestData
|
||||||
|
import com.r3.corda.networkmanage.hsm.signer.HsmCsrSigner
|
||||||
|
import com.r3.corda.networkmanage.hsm.signer.HsmNetworkMapSigner
|
||||||
|
import net.corda.core.crypto.Crypto.generateKeyPair
|
||||||
|
import net.corda.core.crypto.secureRandomBytes
|
||||||
|
import net.corda.core.identity.CordaX500Name.Companion.parse
|
||||||
|
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.createCertificateSigningRequest
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
|
||||||
|
class HsmSigningServiceTest : HsmCertificateTest() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `HSM signing service can sign network map data`() {
|
||||||
|
// when root cert is created
|
||||||
|
run(rootCertParameters)
|
||||||
|
// when network map cert is created
|
||||||
|
run(rootCertParameters.copy(
|
||||||
|
certConfig = rootCertParameters.certConfig.copy(
|
||||||
|
keyGroup = NETWORK_MAP_CERT_KEY_GROUP,
|
||||||
|
rootKeyGroup = ROOT_CERT_KEY_GROUP,
|
||||||
|
certificateType = CertificateType.NETWORK_MAP,
|
||||||
|
subject = NETWORK_MAP_CERT_SUBJECT
|
||||||
|
)
|
||||||
|
))
|
||||||
|
// when doorman cert is created
|
||||||
|
run(rootCertParameters.copy(
|
||||||
|
certConfig = rootCertParameters.certConfig.copy(
|
||||||
|
keyGroup = DOORMAN_CERT_KEY_GROUP,
|
||||||
|
rootKeyGroup = ROOT_CERT_KEY_GROUP,
|
||||||
|
certificateType = CertificateType.INTERMEDIATE_CA,
|
||||||
|
subject = DOORMAN_CERT_SUBJECT
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
// given authenticated user
|
||||||
|
val userInput = givenHsmUserAuthenticationInput()
|
||||||
|
|
||||||
|
// given HSM network map signer
|
||||||
|
val signer = HsmNetworkMapSigner(Authenticator(
|
||||||
|
provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.networkMapKeyGroup),
|
||||||
|
inputReader = userInput))
|
||||||
|
|
||||||
|
// give random data to sign
|
||||||
|
val toSign = secureRandomBytes(10)
|
||||||
|
|
||||||
|
// when
|
||||||
|
signer.signBytes(toSign)
|
||||||
|
|
||||||
|
// No exception is thrown
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `HSM signing service can sign CSR data`() {
|
||||||
|
// when root cert is created
|
||||||
|
run(rootCertParameters)
|
||||||
|
// when network map cert is created
|
||||||
|
run(rootCertParameters.copy(
|
||||||
|
certConfig = rootCertParameters.certConfig.copy(
|
||||||
|
keyGroup = NETWORK_MAP_CERT_KEY_GROUP,
|
||||||
|
rootKeyGroup = ROOT_CERT_KEY_GROUP,
|
||||||
|
certificateType = CertificateType.NETWORK_MAP,
|
||||||
|
subject = NETWORK_MAP_CERT_SUBJECT
|
||||||
|
)
|
||||||
|
))
|
||||||
|
// when doorman cert is created
|
||||||
|
run(rootCertParameters.copy(
|
||||||
|
certConfig = rootCertParameters.certConfig.copy(
|
||||||
|
keyGroup = DOORMAN_CERT_KEY_GROUP,
|
||||||
|
rootKeyGroup = ROOT_CERT_KEY_GROUP,
|
||||||
|
certificateType = CertificateType.INTERMEDIATE_CA,
|
||||||
|
subject = DOORMAN_CERT_SUBJECT
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
// given authenticated user
|
||||||
|
val userInput = givenHsmUserAuthenticationInput()
|
||||||
|
|
||||||
|
// given HSM CSR signer
|
||||||
|
val signer = HsmCsrSigner(
|
||||||
|
mock(),
|
||||||
|
CORDA_INTERMEDIATE_CA,
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
CORDA_ROOT_CA,
|
||||||
|
3650,
|
||||||
|
Authenticator(
|
||||||
|
provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.doormanKeyGroup),
|
||||||
|
rootProvider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.rootKeyGroup),
|
||||||
|
inputReader = userInput)
|
||||||
|
)
|
||||||
|
|
||||||
|
// give random data to sign
|
||||||
|
val toSign = ApprovedCertificateRequestData(
|
||||||
|
"test",
|
||||||
|
createCertificateSigningRequest(
|
||||||
|
parse("O=R3Cev,L=London,C=GB").x500Principal,
|
||||||
|
"my@mail.com",
|
||||||
|
generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME)))
|
||||||
|
|
||||||
|
// when
|
||||||
|
signer.sign(listOf(toSign))
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertNotNull(toSign.certPath)
|
||||||
|
val certificates = toSign.certPath!!.certificates
|
||||||
|
assertEquals(3, certificates.size)
|
||||||
|
}
|
||||||
|
}
|
@ -1,61 +0,0 @@
|
|||||||
package com.r3.corda.networkmanage.hsm
|
|
||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.any
|
|
||||||
import com.nhaarman.mockito_kotlin.mock
|
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
|
||||||
import com.r3.corda.networkmanage.HsmSimulator
|
|
||||||
import com.r3.corda.networkmanage.hsm.authentication.Authenticator
|
|
||||||
import com.r3.corda.networkmanage.hsm.authentication.InputReader
|
|
||||||
import com.r3.corda.networkmanage.hsm.authentication.createProvider
|
|
||||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.rules.TemporaryFolder
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
|
||||||
import kotlin.test.assertTrue
|
|
||||||
|
|
||||||
class HsmTest {
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
@JvmField
|
|
||||||
val hsmSimulator: HsmSimulator = HsmSimulator()
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
@JvmField
|
|
||||||
val tempFolder = TemporaryFolder()
|
|
||||||
|
|
||||||
private val testParameters = Parameters(
|
|
||||||
dataSourceProperties = mock(),
|
|
||||||
device = "${hsmSimulator.port}@${hsmSimulator.host}",
|
|
||||||
keySpecifier = 1,
|
|
||||||
csrPrivateKeyPassword = "",
|
|
||||||
networkMapPrivateKeyPassword = "",
|
|
||||||
rootPrivateKeyPassword = "",
|
|
||||||
keyGroup = "DEV.DOORMAN",
|
|
||||||
validDays = 3650,
|
|
||||||
csrCertCrlDistPoint = "http://test.com/revoked.crl"
|
|
||||||
)
|
|
||||||
|
|
||||||
private lateinit var inputReader: InputReader
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setUp() {
|
|
||||||
inputReader = mock()
|
|
||||||
whenever(inputReader.readLine()).thenReturn(hsmSimulator.cryptoUserCredentials().username)
|
|
||||||
whenever(inputReader.readPassword(any())).thenReturn(hsmSimulator.cryptoUserCredentials().password)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Authenticator executes the block once user is successfully authenticated`() {
|
|
||||||
// given
|
|
||||||
val authenticator = Authenticator(testParameters.createProvider(), inputReader = inputReader)
|
|
||||||
val executed = AtomicBoolean(false)
|
|
||||||
|
|
||||||
// when
|
|
||||||
authenticator.connectAndAuthenticate { _, _ -> executed.set(true) }
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertTrue(executed.get())
|
|
||||||
}
|
|
||||||
}
|
|
@ -57,8 +57,13 @@ fun run(parameters: Parameters) {
|
|||||||
val database = configureDatabase(dataSourceProperties, databaseConfig)
|
val database = configureDatabase(dataSourceProperties, databaseConfig)
|
||||||
val csrStorage = DBSignedCertificateRequestStorage(database)
|
val csrStorage = DBSignedCertificateRequestStorage(database)
|
||||||
val hsmSigner = HsmNetworkMapSigner(
|
val hsmSigner = HsmNetworkMapSigner(
|
||||||
networkMapPrivateKeyPassword,
|
Authenticator(
|
||||||
Authenticator(createProvider(), AuthMode.KEY_FILE, autoUsername, authKeyFilePath, authKeyFilePassword, signAuthThreshold))
|
AuthMode.KEY_FILE,
|
||||||
|
autoUsername,
|
||||||
|
authKeyFilePath,
|
||||||
|
authKeyFilePassword,
|
||||||
|
signAuthThreshold,
|
||||||
|
provider = createProvider(networkMapKeyGroup)))
|
||||||
|
|
||||||
val networkMapStorage = PersistentNetworkMapStorage(database)
|
val networkMapStorage = PersistentNetworkMapStorage(database)
|
||||||
val scheduler = Executors.newSingleThreadScheduledExecutor()
|
val scheduler = Executors.newSingleThreadScheduledExecutor()
|
||||||
@ -68,12 +73,18 @@ fun run(parameters: Parameters) {
|
|||||||
val signer = HsmCsrSigner(
|
val signer = HsmCsrSigner(
|
||||||
csrStorage,
|
csrStorage,
|
||||||
csrCertificateName,
|
csrCertificateName,
|
||||||
csrPrivateKeyPassword,
|
|
||||||
csrCertCrlDistPoint,
|
csrCertCrlDistPoint,
|
||||||
csrCertCrlIssuer,
|
csrCertCrlIssuer,
|
||||||
rootCertificateName,
|
rootCertificateName,
|
||||||
validDays,
|
validDays,
|
||||||
Authenticator(createProvider(), authMode, autoUsername, authKeyFilePath, authKeyFilePassword, signAuthThreshold))
|
Authenticator(
|
||||||
|
authMode,
|
||||||
|
autoUsername,
|
||||||
|
authKeyFilePath,
|
||||||
|
authKeyFilePassword,
|
||||||
|
signAuthThreshold,
|
||||||
|
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", {
|
||||||
@ -141,13 +152,6 @@ private fun confirmedSign(selectedItems: List<ApprovedCertificateRequestData>):
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun confirmedKeyGen(): Boolean {
|
|
||||||
println("Are you sure you want to generate new keys/certificates (it will overwrite the existing ones):")
|
|
||||||
var result = false
|
|
||||||
Menu().addItem("Y", "Yes", { result = true }, true).setExitOption("N", "No").showMenu()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSelection(toSelect: List<ApprovedCertificateRequestData>): List<ApprovedCertificateRequestData> {
|
private fun getSelection(toSelect: List<ApprovedCertificateRequestData>): List<ApprovedCertificateRequestData> {
|
||||||
print("CSRs to be signed (comma separated list): ")
|
print("CSRs to be signed (comma separated list): ")
|
||||||
val line = readLine()
|
val line = readLine()
|
||||||
|
@ -11,22 +11,24 @@ import kotlin.reflect.full.memberProperties
|
|||||||
/**
|
/**
|
||||||
* Performs user authentication against the HSM
|
* Performs user authentication against the HSM
|
||||||
*/
|
*/
|
||||||
class Authenticator(private val provider: CryptoServerProvider,
|
class Authenticator(private val mode: AuthMode = AuthMode.PASSWORD,
|
||||||
private val mode: AuthMode = AuthMode.PASSWORD,
|
|
||||||
private val autoUsername: String? = null,
|
private val autoUsername: String? = null,
|
||||||
private val authKeyFilePath: Path? = null,
|
private val authKeyFilePath: Path? = null,
|
||||||
private val authKeyFilePass: String? = null,
|
private val authKeyFilePass: String? = null,
|
||||||
private val authStrengthThreshold: Int = 2,
|
private val authStrengthThreshold: Int = 2,
|
||||||
inputReader: InputReader = ConsoleInputReader()) : InputReader by inputReader {
|
inputReader: InputReader = ConsoleInputReader(),
|
||||||
|
private val provider: CryptoServerProvider,
|
||||||
|
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 2 parameters:
|
* @param block to be executed once the authentication process succeeds. The block should take 3 parameters:
|
||||||
* 1) [CryptoServerProvider] instance
|
* 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, List<String>) -> T): T {
|
fun <T : Any> connectAndAuthenticate(block: (CryptoServerProvider, CryptoServerProvider?, List<String>) -> T): T {
|
||||||
return try {
|
return try {
|
||||||
val authenticated = mutableListOf<String>()
|
val authenticated = mutableListOf<String>()
|
||||||
loop@ while (true) {
|
loop@ while (true) {
|
||||||
@ -45,7 +47,12 @@ class Authenticator(private val provider: CryptoServerProvider,
|
|||||||
when (mode) {
|
when (mode) {
|
||||||
AuthMode.CARD_READER -> {
|
AuthMode.CARD_READER -> {
|
||||||
println("Authenticating using card reader")
|
println("Authenticating using card reader")
|
||||||
|
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")
|
||||||
@ -60,7 +67,12 @@ class Authenticator(private val provider: CryptoServerProvider,
|
|||||||
} else {
|
} else {
|
||||||
authKeyFilePass
|
authKeyFilePass
|
||||||
}
|
}
|
||||||
|
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")
|
||||||
@ -69,7 +81,12 @@ class Authenticator(private val provider: CryptoServerProvider,
|
|||||||
authenticated.clear()
|
authenticated.clear()
|
||||||
break@loop
|
break@loop
|
||||||
}
|
}
|
||||||
|
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!!)
|
||||||
@ -82,7 +99,7 @@ class Authenticator(private val provider: CryptoServerProvider,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!authenticated.isEmpty()) {
|
if (!authenticated.isEmpty()) {
|
||||||
block(provider, authenticated)
|
block(provider, rootProvider, authenticated)
|
||||||
} else {
|
} else {
|
||||||
throw AuthenticationException()
|
throw AuthenticationException()
|
||||||
}
|
}
|
||||||
@ -114,7 +131,7 @@ data class CryptoServerProviderConfig(
|
|||||||
/**
|
/**
|
||||||
* Creates an instance of [CryptoServerProvider] that corresponds to the HSM.
|
* Creates an instance of [CryptoServerProvider] that corresponds to the HSM.
|
||||||
*/
|
*/
|
||||||
fun Parameters.createProvider(): CryptoServerProvider {
|
fun Parameters.createProvider(keyGroup: String): CryptoServerProvider {
|
||||||
val config = CryptoServerProviderConfig(
|
val config = CryptoServerProviderConfig(
|
||||||
Device = device,
|
Device = device,
|
||||||
KeyGroup = keyGroup,
|
KeyGroup = keyGroup,
|
||||||
|
@ -20,15 +20,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 keyGroup: String,
|
val rootKeyGroup: String,
|
||||||
|
val doormanKeyGroup:String,
|
||||||
|
val networkMapKeyGroup: String,
|
||||||
val keySpecifier: Int = DEFAULT_KEY_SPECIFIER,
|
val keySpecifier: Int = DEFAULT_KEY_SPECIFIER,
|
||||||
val rootPrivateKeyPassword: String,
|
|
||||||
val csrPrivateKeyPassword: String,
|
|
||||||
val csrCertificateName: String = DEFAULT_CSR_CERTIFICATE_NAME,
|
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 networkMapPrivateKeyPassword: String,
|
|
||||||
val rootCertificateName: String = DEFAULT_ROOT_CERTIFICATE_NAME,
|
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,
|
||||||
|
@ -19,7 +19,7 @@ class AutoAuthenticator(providerConfig: CryptoServerProviderConfig,
|
|||||||
fun connectAndAuthenticate(block: (CryptoServerProvider) -> Unit) {
|
fun connectAndAuthenticate(block: (CryptoServerProvider) -> Unit) {
|
||||||
try {
|
try {
|
||||||
for (userConfig in userConfigs) {
|
for (userConfig in userConfigs) {
|
||||||
when(userConfig.authMode) {
|
when (userConfig.authMode) {
|
||||||
AuthMode.PASSWORD -> provider.loginPassword(userConfig.username, userConfig.authToken)
|
AuthMode.PASSWORD -> provider.loginPassword(userConfig.username, userConfig.authToken)
|
||||||
AuthMode.CARD_READER -> provider.loginSign(userConfig.username, ":cs2:cyb:USB0", null)
|
AuthMode.CARD_READER -> provider.loginSign(userConfig.username, ":cs2:cyb:USB0", null)
|
||||||
AuthMode.KEY_FILE -> provider.loginSign(userConfig.username, userConfig.keyFilePassword, userConfig.authToken)
|
AuthMode.KEY_FILE -> provider.loginSign(userConfig.username, userConfig.keyFilePassword, userConfig.authToken)
|
||||||
|
@ -15,7 +15,7 @@ import java.nio.file.Paths
|
|||||||
*/
|
*/
|
||||||
data class UserAuthenticationParameters(val username: String,
|
data class UserAuthenticationParameters(val username: String,
|
||||||
val authMode: AuthMode,
|
val authMode: AuthMode,
|
||||||
val authToken: String, // password or path to the key file, depending on the [authMode]
|
val authToken: String?, // password or path to the key file, depending on the [authMode]
|
||||||
val keyFilePassword: String?) // used only if authMode == [AuthMode.KEY_FILE]
|
val keyFilePassword: String?) // used only if authMode == [AuthMode.KEY_FILE]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,6 +42,7 @@ data class CertificateConfiguration(val keyGroup: String,
|
|||||||
val keySpecifier: Int,
|
val keySpecifier: Int,
|
||||||
val storeKeysExternal: Boolean,
|
val storeKeysExternal: Boolean,
|
||||||
val certificateType: CertificateType,
|
val certificateType: CertificateType,
|
||||||
|
val rootKeyGroup: String?,
|
||||||
val subject: String, // it is certificate [X500Name] subject
|
val subject: String, // it is certificate [X500Name] subject
|
||||||
val validDays: Int,
|
val validDays: Int,
|
||||||
val crlDistributionUrl: String?,
|
val crlDistributionUrl: String?,
|
||||||
|
@ -4,7 +4,6 @@ import CryptoServerCXI.CryptoServerCXI.KEY_ALGO_ECDSA
|
|||||||
import CryptoServerCXI.CryptoServerCXI.KeyAttributes
|
import CryptoServerCXI.CryptoServerCXI.KeyAttributes
|
||||||
import CryptoServerJCE.CryptoServerProvider
|
import CryptoServerJCE.CryptoServerProvider
|
||||||
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.doorman.NETWORK_ROOT_TRUSTSTORE_FILENAME
|
|
||||||
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.createIntermediateCert
|
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.createIntermediateCert
|
||||||
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.createSelfSignedCACert
|
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.createSelfSignedCACert
|
||||||
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.getAndInitializeKeyStore
|
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.getAndInitializeKeyStore
|
||||||
@ -15,10 +14,13 @@ import net.corda.core.internal.div
|
|||||||
import net.corda.core.internal.isDirectory
|
import net.corda.core.internal.isDirectory
|
||||||
import net.corda.core.internal.x500Name
|
import net.corda.core.internal.x500Name
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import net.corda.nodeapi.internal.crypto.*
|
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||||
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_INTERMEDIATE_CA
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
|
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
|
||||||
|
import net.corda.nodeapi.internal.crypto.addOrReplaceCertificate
|
||||||
|
import net.corda.nodeapi.internal.crypto.loadOrCreateKeyStore
|
||||||
|
import net.corda.nodeapi.internal.crypto.save
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.security.Key
|
import java.security.Key
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
@ -27,7 +29,6 @@ import java.security.PrivateKey
|
|||||||
import java.security.cert.Certificate
|
import java.security.cert.Certificate
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
|
|
||||||
data class CertificateNameAndPass(val certificateName: String, val privateKeyPassword: String)
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates logic for key and certificate generation.
|
* Encapsulates logic for key and certificate generation.
|
||||||
*
|
*
|
||||||
@ -37,7 +38,7 @@ class KeyCertificateGenerator(private val parameters: GeneratorParameters) {
|
|||||||
val logger = contextLogger()
|
val logger = contextLogger()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generate(provider: CryptoServerProvider) {
|
fun generate(provider: CryptoServerProvider, rootProvider: CryptoServerProvider? = null) {
|
||||||
parameters.run {
|
parameters.run {
|
||||||
require(trustStoreDirectory.isDirectory()) { "trustStoreDirectory must point to a directory." }
|
require(trustStoreDirectory.isDirectory()) { "trustStoreDirectory must point to a directory." }
|
||||||
val keyName = when (certConfig.certificateType) {
|
val keyName = when (certConfig.certificateType) {
|
||||||
@ -48,10 +49,11 @@ class KeyCertificateGenerator(private val parameters: GeneratorParameters) {
|
|||||||
}
|
}
|
||||||
val keyStore = getAndInitializeKeyStore(provider)
|
val keyStore = getAndInitializeKeyStore(provider)
|
||||||
val keyPair = certConfig.generateEcdsaKeyPair(keyName, provider, keyStore)
|
val keyPair = certConfig.generateEcdsaKeyPair(keyName, provider, keyStore)
|
||||||
val certChain = if (certConfig.certificateType == ROOT_CA) {
|
val certChain = if (rootProvider == null) {
|
||||||
certConfig.generateRootCert(provider, keyPair, trustStoreDirectory, trustStorePassword)
|
certConfig.generateRootCert(provider, keyPair, trustStoreDirectory, trustStorePassword)
|
||||||
} else {
|
} else {
|
||||||
certConfig.generateIntermediateCert(provider, keyPair, keyStore)
|
val rootKeyStore = getAndInitializeKeyStore(rootProvider)
|
||||||
|
certConfig.generateIntermediateCert(rootProvider, keyPair, rootKeyStore)
|
||||||
}
|
}
|
||||||
keyStore.addOrReplaceKey(keyName, keyPair.private, null, certChain)
|
keyStore.addOrReplaceKey(keyName, keyPair.private, null, certChain)
|
||||||
logger.info("New certificate and key pair named $keyName have been generated and stored in HSM")
|
logger.info("New certificate and key pair named $keyName have been generated and stored in HSM")
|
||||||
@ -77,12 +79,13 @@ class KeyCertificateGenerator(private val parameters: GeneratorParameters) {
|
|||||||
provider,
|
provider,
|
||||||
crlDistributionUrl,
|
crlDistributionUrl,
|
||||||
crlIssuer).certificate
|
crlIssuer).certificate
|
||||||
val networkRootTruststorePath = networkRootTrustStoreDirectory / NETWORK_ROOT_TRUSTSTORE_FILENAME
|
logger.info("Certificate for $subject created.")
|
||||||
val networkRootTruststore = loadOrCreateKeyStore(networkRootTruststorePath, networkRootTrustStorePassword)
|
val trustStorePath = networkRootTrustStoreDirectory / "truststore.jks"
|
||||||
logger.info("Trust store for distribution to nodes created in $networkRootTruststorePath")
|
val trustStore = loadOrCreateKeyStore(trustStorePath, networkRootTrustStorePassword)
|
||||||
networkRootTruststore.addOrReplaceCertificate(CORDA_ROOT_CA, certificate)
|
logger.info("Trust store for distribution to nodes created in $trustStore")
|
||||||
logger.info("Certificate $CORDA_ROOT_CA has been added to $networkRootTruststorePath")
|
trustStore.addOrReplaceCertificate(CORDA_ROOT_CA, certificate)
|
||||||
networkRootTruststore.save(networkRootTruststorePath, networkRootTrustStorePassword)
|
logger.info("Certificate $CORDA_ROOT_CA has been added to $trustStore")
|
||||||
|
trustStore.save(trustStorePath, networkRootTrustStorePassword)
|
||||||
logger.info("Trust store has been persisted. Ready for distribution.")
|
logger.info("Trust store has been persisted. Ready for distribution.")
|
||||||
return arrayOf(certificate)
|
return arrayOf(certificate)
|
||||||
}
|
}
|
||||||
@ -90,8 +93,10 @@ class KeyCertificateGenerator(private val parameters: GeneratorParameters) {
|
|||||||
private fun CertificateConfiguration.generateIntermediateCert(
|
private fun CertificateConfiguration.generateIntermediateCert(
|
||||||
provider: CryptoServerProvider,
|
provider: CryptoServerProvider,
|
||||||
keyPair: KeyPair,
|
keyPair: KeyPair,
|
||||||
keyStore: KeyStore): Array<X509Certificate> {
|
rootKeyStore: KeyStore): Array<X509Certificate> {
|
||||||
val rootKeysAndCertChain = retrieveKeysAndCertificateChain(CORDA_ROOT_CA, keyStore)
|
logger.info("Retrieving the root key pair.")
|
||||||
|
val rootKeysAndCertChain = retrieveKeysAndCertificateChain(CORDA_ROOT_CA,
|
||||||
|
rootKeyStore)
|
||||||
val certificateAndKeyPair = createIntermediateCert(
|
val certificateAndKeyPair = createIntermediateCert(
|
||||||
certificateType,
|
certificateType,
|
||||||
CordaX500Name.parse(subject).x500Name,
|
CordaX500Name.parse(subject).x500Name,
|
||||||
@ -101,6 +106,7 @@ class KeyCertificateGenerator(private val parameters: GeneratorParameters) {
|
|||||||
provider,
|
provider,
|
||||||
crlDistributionUrl,
|
crlDistributionUrl,
|
||||||
crlIssuer)
|
crlIssuer)
|
||||||
|
logger.info("Certificate for $subject created.")
|
||||||
return arrayOf(certificateAndKeyPair.certificate, *rootKeysAndCertChain.certificateChain)
|
return arrayOf(certificateAndKeyPair.certificate, *rootKeysAndCertChain.certificateChain)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,8 +120,9 @@ class KeyCertificateGenerator(private val parameters: GeneratorParameters) {
|
|||||||
name = keyName
|
name = keyName
|
||||||
setCurve(keyCurve)
|
setCurve(keyCurve)
|
||||||
}
|
}
|
||||||
logger.info("Generating key $keyName")
|
logger.info("Generating key $keyName.")
|
||||||
provider.cryptoServer.generateKey(keyOverride, keyAttributes, keyGenMechanism)
|
provider.cryptoServer.generateKey(keyOverride, keyAttributes, keyGenMechanism)
|
||||||
|
logger.info("$keyName key generated.")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CertificateConfiguration.generateEcdsaKeyPair(keyName: String, provider: CryptoServerProvider, keyStore: KeyStore): KeyPair {
|
private fun CertificateConfiguration.generateEcdsaKeyPair(keyName: String, provider: CryptoServerProvider, keyStore: KeyStore): KeyPair {
|
||||||
|
@ -2,24 +2,40 @@ package com.r3.corda.networkmanage.hsm.generator
|
|||||||
|
|
||||||
import com.r3.corda.networkmanage.hsm.authentication.CryptoServerProviderConfig
|
import com.r3.corda.networkmanage.hsm.authentication.CryptoServerProviderConfig
|
||||||
import com.r3.corda.networkmanage.hsm.utils.mapCryptoServerException
|
import com.r3.corda.networkmanage.hsm.utils.mapCryptoServerException
|
||||||
|
import net.corda.nodeapi.internal.crypto.CertificateType.ROOT_CA
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import java.nio.file.Paths
|
|
||||||
|
|
||||||
private val log = LogManager.getLogger("com.r3.corda.networkmanage.hsm.generator.Main")
|
private val log = LogManager.getLogger("com.r3.corda.networkmanage.hsm.generator.Main")
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val commandLineOptions = parseCommandLine(*args)
|
run(parseParameters(parseCommandLine(*args).configFile))
|
||||||
parseParameters(commandLineOptions.configFile).run {
|
}
|
||||||
|
|
||||||
|
fun run(parameters: GeneratorParameters) {
|
||||||
|
parameters.run {
|
||||||
val providerConfig = CryptoServerProviderConfig(
|
val providerConfig = CryptoServerProviderConfig(
|
||||||
Device = "$hsmPort@$hsmHost",
|
Device = "$hsmPort@$hsmHost",
|
||||||
KeySpecifier = certConfig.keySpecifier,
|
KeySpecifier = certConfig.keySpecifier,
|
||||||
KeyGroup = certConfig.keyGroup,
|
KeyGroup = certConfig.keyGroup,
|
||||||
StoreKeysExternal = certConfig.storeKeysExternal)
|
StoreKeysExternal = certConfig.storeKeysExternal)
|
||||||
try {
|
try {
|
||||||
val authenticator = AutoAuthenticator(providerConfig, userConfigs)
|
AutoAuthenticator(providerConfig, userConfigs).connectAndAuthenticate { provider ->
|
||||||
authenticator.connectAndAuthenticate { provider ->
|
|
||||||
val generator = KeyCertificateGenerator(this)
|
val generator = KeyCertificateGenerator(this)
|
||||||
|
if (certConfig.certificateType == ROOT_CA) {
|
||||||
generator.generate(provider)
|
generator.generate(provider)
|
||||||
|
} else {
|
||||||
|
requireNotNull(certConfig.rootKeyGroup)
|
||||||
|
val rootProviderConfig = CryptoServerProviderConfig(
|
||||||
|
Device = "$hsmPort@$hsmHost",
|
||||||
|
KeySpecifier = certConfig.keySpecifier,
|
||||||
|
KeyGroup = certConfig.rootKeyGroup!!,
|
||||||
|
StoreKeysExternal = certConfig.storeKeysExternal)
|
||||||
|
AutoAuthenticator(rootProviderConfig, userConfigs).connectAndAuthenticate { rootProvider ->
|
||||||
|
generator.generate(provider, rootProvider)
|
||||||
|
rootProvider.logoff()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
provider.logoff()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.error(mapCryptoServerException(e))
|
log.error(mapCryptoServerException(e))
|
||||||
|
@ -14,7 +14,6 @@ import net.corda.nodeapi.internal.crypto.CertificateType
|
|||||||
*/
|
*/
|
||||||
class HsmCsrSigner(private val storage: SignedCertificateRequestStorage,
|
class HsmCsrSigner(private val storage: SignedCertificateRequestStorage,
|
||||||
private val intermediateCertAlias: String,
|
private val intermediateCertAlias: String,
|
||||||
private val intermediateCertPrivateKeyPass: String?,
|
|
||||||
private val csrCertCrlDistPoint: String,
|
private val csrCertCrlDistPoint: String,
|
||||||
private val csrCertCrlIssuer: String?,
|
private val csrCertCrlIssuer: String?,
|
||||||
private val rootCertAlias: String,
|
private val rootCertAlias: String,
|
||||||
@ -32,22 +31,22 @@ 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, signers ->
|
authenticator.connectAndAuthenticate { provider, rootProvider, signers ->
|
||||||
val keyStore = getAndInitializeKeyStore(provider)
|
val rootKeyStore = getAndInitializeKeyStore(rootProvider!!)
|
||||||
// This should be changed once we allow for more certificates in the chain. Preferably we should use
|
// 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).
|
// keyStore.getCertificateChain(String) and assume entire chain is stored in the HSM (depending on the support).
|
||||||
val rootCert = keyStore.getCertificate(rootCertAlias)
|
val rootCert = rootKeyStore.getCertificate(rootCertAlias)
|
||||||
val intermediatePrivateKeyPass = intermediateCertPrivateKeyPass ?: authenticator.readPassword("CA Private Key Password: ")
|
val keyStore = getAndInitializeKeyStore(provider)
|
||||||
val intermediateCertAndKey = retrieveCertificateAndKeys(intermediateCertAlias, intermediatePrivateKeyPass, keyStore)
|
val doormanCertAndKey = retrieveCertificateAndKeys(intermediateCertAlias, keyStore)
|
||||||
toSign.forEach {
|
toSign.forEach {
|
||||||
it.certPath = buildCertPath(createClientCertificate(
|
it.certPath = buildCertPath(createClientCertificate(
|
||||||
CertificateType.NODE_CA,
|
CertificateType.NODE_CA,
|
||||||
intermediateCertAndKey,
|
doormanCertAndKey,
|
||||||
it.request,
|
it.request,
|
||||||
validDays,
|
validDays,
|
||||||
provider,
|
provider,
|
||||||
csrCertCrlDistPoint,
|
csrCertCrlDistPoint,
|
||||||
csrCertCrlIssuer), rootCert)
|
csrCertCrlIssuer), doormanCertAndKey.certificate, rootCert)
|
||||||
}
|
}
|
||||||
storage.store(toSign, signers)
|
storage.store(toSign, signers)
|
||||||
println("The following certificates have been signed by $signers:")
|
println("The following certificates have been signed by $signers:")
|
||||||
|
@ -15,18 +15,17 @@ import java.security.Signature
|
|||||||
* Signer which connects to a HSM using the given [authenticator] to sign bytes.
|
* Signer which connects to a HSM using the given [authenticator] to sign bytes.
|
||||||
*/
|
*/
|
||||||
// TODO Rename this to HsmSigner
|
// TODO Rename this to HsmSigner
|
||||||
class HsmNetworkMapSigner(private val privateKeyPassword: String,
|
class HsmNetworkMapSigner(private val authenticator: Authenticator) : Signer {
|
||||||
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
|
||||||
// when used with the given provider.
|
// when used with the given provider.
|
||||||
val key = keyStore.getKey(CORDA_NETWORK_MAP, privateKeyPassword.toCharArray()) as PrivateKey
|
val key = keyStore.getKey(CORDA_NETWORK_MAP, null) as PrivateKey
|
||||||
val signature = Signature.getInstance(HsmX509Utilities.SIGNATURE_ALGORITHM, provider).run {
|
val signature = Signature.getInstance(HsmX509Utilities.SIGNATURE_ALGORITHM, provider).run {
|
||||||
initSign(key)
|
initSign(key)
|
||||||
update(data)
|
update(data)
|
||||||
|
@ -101,12 +101,11 @@ object HsmX509Utilities {
|
|||||||
* Retrieves a certificate and keys from the given key store. Also, the keys retrieved are cleaned in a sense of the
|
* Retrieves a certificate and keys from the given key store. Also, the keys retrieved are cleaned in a sense of the
|
||||||
* [getCleanEcdsaKeyPair] method.
|
* [getCleanEcdsaKeyPair] method.
|
||||||
* @param certificateKeyName certificate and key name (alias) to be used when querying the key store.
|
* @param certificateKeyName certificate and key name (alias) to be used when querying the key store.
|
||||||
* @param privateKeyPassword password for the private key.
|
|
||||||
* @param keyStore key store that holds the certificate with its keys.
|
* @param keyStore key store that holds the certificate with its keys.
|
||||||
* @return instance of [CertificateAndKeyPair] holding the retrieved certificate with its keys.
|
* @return instance of [CertificateAndKeyPair] holding the retrieved certificate with its keys.
|
||||||
*/
|
*/
|
||||||
fun retrieveCertificateAndKeys(certificateKeyName: String, privateKeyPassword: String, keyStore: KeyStore): CertificateAndKeyPair {
|
fun retrieveCertificateAndKeys(certificateKeyName: String, keyStore: KeyStore): CertificateAndKeyPair {
|
||||||
val privateKey = keyStore.getKey(certificateKeyName, privateKeyPassword.toCharArray()) as PrivateKey
|
val privateKey = keyStore.getKey(certificateKeyName, null) as PrivateKey
|
||||||
val publicKey = keyStore.getCertificate(certificateKeyName).publicKey
|
val publicKey = keyStore.getCertificate(certificateKeyName).publicKey
|
||||||
val certificate = keyStore.getX509Certificate(certificateKeyName)
|
val certificate = keyStore.getX509Certificate(certificateKeyName)
|
||||||
return CertificateAndKeyPair(certificate, getCleanEcdsaKeyPair(publicKey, privateKey))
|
return CertificateAndKeyPair(certificate, getCleanEcdsaKeyPair(publicKey, privateKey))
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
device = "3001@127.0.0.1"
|
|
||||||
keyGroup = "*"
|
|
||||||
keySpecifier = -1
|
|
||||||
authMode = PASSWORD
|
|
||||||
csrPrivateKeyPassword = ""
|
|
||||||
networkMapPrivateKeyPassword = ""
|
|
||||||
rootPrivateKeyPassword = ""
|
|
||||||
keyGroup = "DEV.DOORMAN"
|
|
||||||
validDays = 3650
|
|
||||||
|
|
||||||
h2port = 0
|
|
||||||
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" = ""
|
|
||||||
}
|
|
@ -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)
|
||||||
|
@ -10,7 +10,7 @@ import kotlin.test.assertEquals
|
|||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
|
|
||||||
class ConfigurationTest : TestBase() {
|
class ConfigurationTest : TestBase() {
|
||||||
private val validConfigPath = File(javaClass.getResource("/hsm.conf").toURI()).absolutePath
|
private val validConfigPath = File("./hsm.conf").absolutePath
|
||||||
private val invalidConfigPath = File(javaClass.getResource("/hsm_fail.conf").toURI()).absolutePath
|
private val invalidConfigPath = File(javaClass.getResource("/hsm_fail.conf").toURI()).absolutePath
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
device = "3001@192.168.0.1"
|
|
||||||
keyGroup = "DEV.DOORMAN"
|
|
||||||
keySpecifier = -1
|
|
||||||
authMode = PASSWORD
|
|
||||||
csrPrivateKeyPassword = ""
|
|
||||||
csrCertCrlDistPoint = "http://test.com/revoked.crl"
|
|
||||||
networkMapPrivateKeyPassword = ""
|
|
||||||
rootPrivateKeyPassword = ""
|
|
||||||
keyGroup = "DEV.DOORMAN"
|
|
||||||
validDays = 3650
|
|
||||||
|
|
||||||
h2port = 0
|
|
||||||
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" = ""
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user