mirror of
https://github.com/corda/corda.git
synced 2025-04-27 22:39:44 +00:00
Adding HSM permissions related tests (#448)
* Adding HSM permission tests * Addressing review comments
This commit is contained in:
parent
3baa15960f
commit
73fbff6c4f
@ -39,7 +39,24 @@ class HsmSimulator(private val serverAddress: String = DEFAULT_SERVER_ADDRESS,
|
|||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
val DEFAULT_SERVER_ADDRESS = "corda.azurecr.io"
|
val DEFAULT_SERVER_ADDRESS = "corda.azurecr.io"
|
||||||
val DEFAULT_IMAGE_REPO_TAG = "corda.azurecr.io/network-management/hsm-simulator"
|
/*
|
||||||
|
* Currently we have following images:
|
||||||
|
* 1) corda.azurecr.io/network-management/hsm-simulator - having only one user configured:
|
||||||
|
* - INTEGRATION_TEST (password: INTEGRATION_TEST) with the CXI_GROUP="*"
|
||||||
|
* 2)corda.azurecr.io/network-management/hsm-simulator-with-groups - having following users configured:
|
||||||
|
* - INTEGRATION_TEST (password: INTEGRATION_TEST) with the CXI_GROUP=*
|
||||||
|
* - INTEGRATION_TEST_SUPER (password: INTEGRATION_TEST) with the CXI_GROUP=TEST.CORDACONNECT
|
||||||
|
* - INTEGRATION_TEST_ROOT (password: INTEGRATION_TEST) with the CXI_GROUP=TEST.CORDACONNECT.ROOT
|
||||||
|
* - INTEGRATION_TEST_OPS (password: INTEGRATION_TEST) with the CXI_GROUP=TEST.CORDACONNECT.OPS
|
||||||
|
* - INTEGRATION_TEST_SUPER_ (password: INTEGRATION_TEST) with the CXI_GROUP=TEST.CORDACONNECT.*
|
||||||
|
* - INTEGRATION_TEST_ROOT_ (password: INTEGRATION_TEST) with the CXI_GROUP=TEST.CORDACONNECT.ROOT.*
|
||||||
|
* - INTEGRATION_TEST_OPS_ (password: INTEGRATION_TEST) with the CXI_GROUP=TEST.CORDACONNECT.OPS.*
|
||||||
|
* - INTEGRATION_TEST_OPS_CERT (password: INTEGRATION_TEST) with the CXI_GROUP=TEST.CORDACONNECT.OPS.CERT
|
||||||
|
* - INTEGRATION_TEST_OPS_NETMAP (password: INTEGRATION_TEST) with the CXI_GROUP=TEST.CORDACONNECT.OPS.NETMAP
|
||||||
|
* - INTEGRATION_TEST_OPS_CERT (password: INTEGRATION_TEST) with the CXI_GROUP=TEST.CORDACONNECT.OPS.CERT.*
|
||||||
|
* - INTEGRATION_TEST_OPS_NETMAP (password: INTEGRATION_TEST) with the CXI_GROUP=TEST.CORDACONNECT.OPS.NETMAP.*
|
||||||
|
*/
|
||||||
|
val DEFAULT_IMAGE_REPO_TAG = "corda.azurecr.io/network-management/hsm-simulator-with-groups"
|
||||||
val DEFAULT_IMAGE_VERSION = "latest"
|
val DEFAULT_IMAGE_VERSION = "latest"
|
||||||
val DEFAULT_PULL_IMAGE = true
|
val DEFAULT_PULL_IMAGE = true
|
||||||
|
|
||||||
|
@ -21,18 +21,44 @@ import java.util.*
|
|||||||
|
|
||||||
abstract class HsmBaseTest {
|
abstract class HsmBaseTest {
|
||||||
companion object {
|
companion object {
|
||||||
const val ROOT_CERT_KEY_GROUP = "DEV.CORDACONNECT.ROOT"
|
const val ROOT_CERT_KEY_GROUP = "TEST.CORDACONNECT.ROOT"
|
||||||
const val NETWORK_MAP_CERT_KEY_GROUP = "DEV.CORDACONNECT.OPS.NETMAP"
|
const val NETWORK_MAP_CERT_KEY_GROUP = "TEST.CORDACONNECT.OPS.NETMAP"
|
||||||
const val DOORMAN_CERT_KEY_GROUP = "DEV.CORDACONNECT.OPS.CERT"
|
const val DOORMAN_CERT_KEY_GROUP = "TEST.CORDACONNECT.OPS.CERT"
|
||||||
const 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 Ltd, OU=Corda, L=London, C=GB"
|
||||||
const 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 Ltd, OU=Corda, L=London, C=GB"
|
||||||
const 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 Ltd, OU=Corda, L=London, C=GB"
|
||||||
val HSM_USER_CONFIGS = listOf(UserAuthenticationParameters(
|
const val TRUSTSTORE_PASSWORD: String = "trustpass"
|
||||||
username = "INTEGRATION_TEST",
|
const val HSM_USERNAME = "INTEGRATION_TEST"
|
||||||
authMode = AuthMode.PASSWORD,
|
const val HSM_PASSWORD = "INTEGRATION_TEST"
|
||||||
authToken = "INTEGRATION_TEST",
|
const val HSM_USERNAME_SUPER = "INTEGRATION_TEST_SUPER"
|
||||||
keyFilePassword = null))
|
const val HSM_USERNAME_OPS = "INTEGRATION_TEST_OPS"
|
||||||
const val ROOT_KEYSTORE_PASSWORD: String = "trustpass"
|
const val HSM_USERNAME_ROOT = "INTEGRATION_TEST_ROOT"
|
||||||
|
const val HSM_USERNAME_SUPER_ = "INTEGRATION_TEST_SUPER_"
|
||||||
|
const val HSM_USERNAME_OPS_ = "INTEGRATION_TEST_OPS_"
|
||||||
|
const val HSM_USERNAME_ROOT_ = "INTEGRATION_TEST_ROOT_"
|
||||||
|
const val HSM_USERNAME_OPS_CERT = "INTEGRATION_TEST_OPS_CERT"
|
||||||
|
const val HSM_USERNAME_OPS_NETMAP = "INTEGRATION_TEST_OPS_NETMAP"
|
||||||
|
const val HSM_USERNAME_OPS_CERT_ = "INTEGRATION_TEST_OPS_CERT_"
|
||||||
|
const val HSM_USERNAME_OPS_NETMAP_ = "INTEGRATION_TEST_OPS_NETMAP_"
|
||||||
|
val HSM_USER_CONFIGS = createHsmUserConfigs(HSM_USERNAME)
|
||||||
|
val HSM_SUPER_USER_CONFIGS = createHsmUserConfigs(HSM_USERNAME_SUPER)
|
||||||
|
val HSM_ROOT_USER_CONFIGS = createHsmUserConfigs(HSM_USERNAME_ROOT)
|
||||||
|
val HSM_OPS_USER_CONFIGS = createHsmUserConfigs(HSM_USERNAME_OPS)
|
||||||
|
val HSM_SUPER__USER_CONFIGS = createHsmUserConfigs(HSM_USERNAME_SUPER_)
|
||||||
|
val HSM_ROOT__USER_CONFIGS = createHsmUserConfigs(HSM_USERNAME_ROOT_)
|
||||||
|
val HSM_OPS__USER_CONFIGS = createHsmUserConfigs(HSM_USERNAME_OPS_)
|
||||||
|
val HSM_OPS_CERT_USER_CONFIGS = createHsmUserConfigs(HSM_USERNAME_OPS_CERT)
|
||||||
|
val HSM_OPS_NETMAP_USER_CONFIGS = createHsmUserConfigs(HSM_USERNAME_OPS_NETMAP)
|
||||||
|
val HSM_OPS_CERT__USER_CONFIGS = createHsmUserConfigs(HSM_USERNAME_OPS_CERT_)
|
||||||
|
val HSM_OPS_NETMAP__USER_CONFIGS = createHsmUserConfigs(HSM_USERNAME_OPS_NETMAP_)
|
||||||
|
|
||||||
|
private fun createHsmUserConfigs(username: String): List<UserAuthenticationParameters> {
|
||||||
|
return listOf(UserAuthenticationParameters(
|
||||||
|
username = username,
|
||||||
|
authMode = AuthMode.PASSWORD,
|
||||||
|
authToken = "INTEGRATION_TEST",
|
||||||
|
keyFilePassword = null))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected lateinit var rootKeyStoreFile: Path
|
protected lateinit var rootKeyStoreFile: Path
|
||||||
@ -53,13 +79,14 @@ abstract class HsmBaseTest {
|
|||||||
dbName = random63BitValue().toString()
|
dbName = random63BitValue().toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createGeneratorParameters(certConfig: CertificateConfiguration): GeneratorParameters {
|
private fun createGeneratorParameters(certConfig: CertificateConfiguration,
|
||||||
|
userConfigs: List<UserAuthenticationParameters>): GeneratorParameters {
|
||||||
return GeneratorParameters(
|
return GeneratorParameters(
|
||||||
hsmHost = hsmSimulator.host,
|
hsmHost = hsmSimulator.host,
|
||||||
hsmPort = hsmSimulator.port,
|
hsmPort = hsmSimulator.port,
|
||||||
trustStoreDirectory = rootKeyStoreFile.parent,
|
trustStoreDirectory = rootKeyStoreFile.parent,
|
||||||
trustStorePassword = ROOT_KEYSTORE_PASSWORD,
|
trustStorePassword = TRUSTSTORE_PASSWORD,
|
||||||
userConfigs = HSM_USER_CONFIGS,
|
userConfigs = userConfigs,
|
||||||
certConfig = certConfig
|
certConfig = certConfig
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -67,7 +94,8 @@ abstract class HsmBaseTest {
|
|||||||
protected fun createGeneratorParameters(keyGroup: String,
|
protected fun createGeneratorParameters(keyGroup: String,
|
||||||
rootKeyGroup: String?,
|
rootKeyGroup: String?,
|
||||||
certificateType: CertificateType,
|
certificateType: CertificateType,
|
||||||
subject: String): GeneratorParameters {
|
subject: String,
|
||||||
|
hsmUserConfigs: List<UserAuthenticationParameters> = HSM_USER_CONFIGS): GeneratorParameters {
|
||||||
return createGeneratorParameters(CertificateConfiguration(
|
return createGeneratorParameters(CertificateConfiguration(
|
||||||
keySpecifier = 1,
|
keySpecifier = 1,
|
||||||
keyGroup = keyGroup,
|
keyGroup = keyGroup,
|
||||||
@ -82,7 +110,7 @@ abstract class HsmBaseTest {
|
|||||||
keyOverride = 0,
|
keyOverride = 0,
|
||||||
crlIssuer = null,
|
crlIssuer = null,
|
||||||
crlDistributionUrl = null
|
crlDistributionUrl = null
|
||||||
))
|
), hsmUserConfigs)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun createHsmSigningServiceConfig(): Parameters {
|
protected fun createHsmSigningServiceConfig(): Parameters {
|
||||||
@ -91,7 +119,7 @@ abstract class HsmBaseTest {
|
|||||||
device = "${hsmSimulator.port}@${hsmSimulator.host}",
|
device = "${hsmSimulator.port}@${hsmSimulator.host}",
|
||||||
keySpecifier = 1,
|
keySpecifier = 1,
|
||||||
rootKeyStoreFile = rootKeyStoreFile,
|
rootKeyStoreFile = rootKeyStoreFile,
|
||||||
rootKeyStorePassword = ROOT_KEYSTORE_PASSWORD,
|
rootKeyStorePassword = TRUSTSTORE_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,
|
||||||
@ -99,10 +127,11 @@ abstract class HsmBaseTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun givenHsmUserAuthenticationInput(): InputReader {
|
protected fun givenHsmUserAuthenticationInput(username: String = HSM_USERNAME,
|
||||||
|
password: String = HSM_PASSWORD): InputReader {
|
||||||
val inputReader = mock<InputReader>()
|
val inputReader = mock<InputReader>()
|
||||||
whenever(inputReader.readLine()).thenReturn(hsmSimulator.cryptoUserCredentials().username)
|
whenever(inputReader.readLine()).thenReturn(username)
|
||||||
whenever(inputReader.readPassword(any())).thenReturn(hsmSimulator.cryptoUserCredentials().password)
|
whenever(inputReader.readPassword(any())).thenReturn(password)
|
||||||
return inputReader
|
return inputReader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,158 @@
|
|||||||
|
package com.r3.corda.networkmanage.hsm
|
||||||
|
|
||||||
|
import com.nhaarman.mockito_kotlin.mock
|
||||||
|
import com.r3.corda.networkmanage.common.HsmBaseTest
|
||||||
|
import com.r3.corda.networkmanage.hsm.authentication.Authenticator
|
||||||
|
import com.r3.corda.networkmanage.hsm.authentication.createProvider
|
||||||
|
import com.r3.corda.networkmanage.hsm.generator.UserAuthenticationParameters
|
||||||
|
import com.r3.corda.networkmanage.hsm.generator.run
|
||||||
|
import com.r3.corda.networkmanage.hsm.persistence.ApprovedCertificateRequestData
|
||||||
|
import com.r3.corda.networkmanage.hsm.signer.HsmCsrSigner
|
||||||
|
import net.corda.core.crypto.Crypto.generateKeyPair
|
||||||
|
import net.corda.core.identity.CordaX500Name.Companion.parse
|
||||||
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
|
import net.corda.nodeapi.internal.crypto.X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME
|
||||||
|
import net.corda.nodeapi.internal.crypto.X509Utilities.createCertificateSigningRequest
|
||||||
|
import org.junit.Test
|
||||||
|
import java.security.GeneralSecurityException
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
|
||||||
|
class HsmPermissionTest : HsmBaseTest() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test case scenario reflects the issue observed on 02.02.2018, when permissions user CXI_GROUP permissions
|
||||||
|
* were wrongly configured on the PROD HSM box.
|
||||||
|
*
|
||||||
|
* Key groups are as follows:
|
||||||
|
* "TEST.CORDACONNECT.ROOT"
|
||||||
|
* "TEST.CORDACONNECT.OPS.NETMAP"
|
||||||
|
* "TEST.CORDACONNECT.OPS.CERT"
|
||||||
|
*
|
||||||
|
* User CXI_GROUP configurations are as follows:
|
||||||
|
* Root cert creator: TEST.CORDACONNECT.*
|
||||||
|
* Doorman cert creator: TEST.CORDACONNECT.*
|
||||||
|
* Networkmap cert creator: TEST.CORDACONNECT.*
|
||||||
|
*
|
||||||
|
* CSR signing user CXI_GROUP is as follows:
|
||||||
|
* TEST.CORDACONNECT.OPS.CERT.*
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun `HSM signing service cannot sign CSR data when HSM user CXI_GROUP permissions are wrongly configured`() {
|
||||||
|
// given certs created
|
||||||
|
givenCertificatesCreated(HSM_SUPER__USER_CONFIGS, HSM_SUPER__USER_CONFIGS, HSM_SUPER__USER_CONFIGS)
|
||||||
|
// given authenticated user
|
||||||
|
val userInput = givenHsmUserAuthenticationInput(HSM_USERNAME_OPS_CERT_)
|
||||||
|
|
||||||
|
// given HSM CSR signer
|
||||||
|
val hsmSigningServiceConfig = createHsmSigningServiceConfig()
|
||||||
|
val signer = HsmCsrSigner(
|
||||||
|
mock(),
|
||||||
|
hsmSigningServiceConfig.loadRootKeyStore(),
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
3650,
|
||||||
|
Authenticator(
|
||||||
|
provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.doormanKeyGroup),
|
||||||
|
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)))
|
||||||
|
|
||||||
|
// then
|
||||||
|
// The GeneralSecurityException is thrown by the JCE layer.
|
||||||
|
// This exception is caused by the CryptoServerException with code B0680001 - permission denied.
|
||||||
|
assertFailsWith(GeneralSecurityException::class) {
|
||||||
|
signer.sign(listOf(toSign))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test case scenario reflects the fix for the issue observed on 02.02.2018, when permissions user CXI_GROUP permissions
|
||||||
|
* were wrongly configured on the PROD HSM box.
|
||||||
|
*
|
||||||
|
* Key groups are as follows:
|
||||||
|
* "TEST.CORDACONNECT.ROOT"
|
||||||
|
* "TEST.CORDACONNECT.OPS.NETMAP"
|
||||||
|
* "TEST.CORDACONNECT.OPS.CERT"
|
||||||
|
*
|
||||||
|
* User CXI_GROUP configurations are as follows:
|
||||||
|
* Root cert creator: TEST.CORDACONNECT.*
|
||||||
|
* Doorman cert creator: TEST.CORDACONNECT.*
|
||||||
|
* Networkmap cert creator: TEST.CORDACONNECT.*
|
||||||
|
*
|
||||||
|
* CSR signing user CXI_GROUP is as follows:
|
||||||
|
* TEST.CORDACONNECT.OPS.CERT
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun `HSM signing service signs CSR data when HSM user CXI_GROUP permissions are correctly configured`() {
|
||||||
|
// given certs created
|
||||||
|
givenCertificatesCreated(HSM_SUPER__USER_CONFIGS, HSM_SUPER__USER_CONFIGS, HSM_SUPER__USER_CONFIGS)
|
||||||
|
// given authenticated user
|
||||||
|
val userInput = givenHsmUserAuthenticationInput(HSM_USERNAME_OPS_CERT)
|
||||||
|
|
||||||
|
// given HSM CSR signer
|
||||||
|
val hsmSigningServiceConfig = createHsmSigningServiceConfig()
|
||||||
|
val signer = HsmCsrSigner(
|
||||||
|
mock(),
|
||||||
|
hsmSigningServiceConfig.loadRootKeyStore(),
|
||||||
|
"trustpass",
|
||||||
|
null,
|
||||||
|
3650,
|
||||||
|
Authenticator(
|
||||||
|
provider = hsmSigningServiceConfig.createProvider(hsmSigningServiceConfig.doormanKeyGroup),
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun givenCertificatesCreated(rootCertUserConfigs: List<UserAuthenticationParameters>,
|
||||||
|
doormanCertUserConfigs: List<UserAuthenticationParameters>,
|
||||||
|
netMapCertUserConfigs: List<UserAuthenticationParameters>) {
|
||||||
|
// when root cert is created
|
||||||
|
run(createGeneratorParameters(
|
||||||
|
keyGroup = HsmBaseTest.ROOT_CERT_KEY_GROUP,
|
||||||
|
rootKeyGroup = null,
|
||||||
|
certificateType = CertificateType.ROOT_CA,
|
||||||
|
subject = HsmBaseTest.ROOT_CERT_SUBJECT,
|
||||||
|
hsmUserConfigs = rootCertUserConfigs))
|
||||||
|
// when network map cert is created
|
||||||
|
run(createGeneratorParameters(
|
||||||
|
keyGroup = HsmBaseTest.NETWORK_MAP_CERT_KEY_GROUP,
|
||||||
|
rootKeyGroup = HsmBaseTest.ROOT_CERT_KEY_GROUP,
|
||||||
|
certificateType = CertificateType.NETWORK_MAP,
|
||||||
|
subject = HsmBaseTest.NETWORK_MAP_CERT_SUBJECT,
|
||||||
|
hsmUserConfigs = netMapCertUserConfigs
|
||||||
|
))
|
||||||
|
// when doorman cert is created
|
||||||
|
run(createGeneratorParameters(
|
||||||
|
keyGroup = HsmBaseTest.DOORMAN_CERT_KEY_GROUP,
|
||||||
|
rootKeyGroup = HsmBaseTest.ROOT_CERT_KEY_GROUP,
|
||||||
|
certificateType = CertificateType.INTERMEDIATE_CA,
|
||||||
|
subject = HsmBaseTest.DOORMAN_CERT_SUBJECT,
|
||||||
|
hsmUserConfigs = doormanCertUserConfigs
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
@ -31,7 +31,7 @@ class HsmSigningServiceTest : HsmBaseTest() {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
loadOrCreateKeyStore(rootKeyStoreFile, ROOT_KEYSTORE_PASSWORD)
|
loadOrCreateKeyStore(rootKeyStoreFile, TRUSTSTORE_PASSWORD)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user