Adding HSM permissions related tests (#448)

* Adding HSM permission tests

* Addressing review comments
This commit is contained in:
Michal Kit 2018-02-06 13:55:32 +00:00 committed by GitHub
parent 3baa15960f
commit 73fbff6c4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 227 additions and 23 deletions

View File

@ -39,7 +39,24 @@ class HsmSimulator(private val serverAddress: String = DEFAULT_SERVER_ADDRESS,
private companion object {
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_PULL_IMAGE = true

View File

@ -21,18 +21,44 @@ import java.util.*
abstract class HsmBaseTest {
companion object {
const val ROOT_CERT_KEY_GROUP = "DEV.CORDACONNECT.ROOT"
const val NETWORK_MAP_CERT_KEY_GROUP = "DEV.CORDACONNECT.OPS.NETMAP"
const val DOORMAN_CERT_KEY_GROUP = "DEV.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 NETWORK_MAP_CERT_SUBJECT = "CN=Corda Network Map, 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(
username = "INTEGRATION_TEST",
authMode = AuthMode.PASSWORD,
authToken = "INTEGRATION_TEST",
keyFilePassword = null))
const val ROOT_KEYSTORE_PASSWORD: String = "trustpass"
const val ROOT_CERT_KEY_GROUP = "TEST.CORDACONNECT.ROOT"
const val NETWORK_MAP_CERT_KEY_GROUP = "TEST.CORDACONNECT.OPS.NETMAP"
const val DOORMAN_CERT_KEY_GROUP = "TEST.CORDACONNECT.OPS.CERT"
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 Ltd, OU=Corda, L=London, C=GB"
const val DOORMAN_CERT_SUBJECT = "CN=Corda Doorman CA, O=R3 Ltd, OU=Corda, L=London, C=GB"
const val TRUSTSTORE_PASSWORD: String = "trustpass"
const val HSM_USERNAME = "INTEGRATION_TEST"
const val HSM_PASSWORD = "INTEGRATION_TEST"
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_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
@ -53,13 +79,14 @@ abstract class HsmBaseTest {
dbName = random63BitValue().toString()
}
private fun createGeneratorParameters(certConfig: CertificateConfiguration): GeneratorParameters {
private fun createGeneratorParameters(certConfig: CertificateConfiguration,
userConfigs: List<UserAuthenticationParameters>): GeneratorParameters {
return GeneratorParameters(
hsmHost = hsmSimulator.host,
hsmPort = hsmSimulator.port,
trustStoreDirectory = rootKeyStoreFile.parent,
trustStorePassword = ROOT_KEYSTORE_PASSWORD,
userConfigs = HSM_USER_CONFIGS,
trustStorePassword = TRUSTSTORE_PASSWORD,
userConfigs = userConfigs,
certConfig = certConfig
)
}
@ -67,7 +94,8 @@ abstract class HsmBaseTest {
protected fun createGeneratorParameters(keyGroup: String,
rootKeyGroup: String?,
certificateType: CertificateType,
subject: String): GeneratorParameters {
subject: String,
hsmUserConfigs: List<UserAuthenticationParameters> = HSM_USER_CONFIGS): GeneratorParameters {
return createGeneratorParameters(CertificateConfiguration(
keySpecifier = 1,
keyGroup = keyGroup,
@ -82,7 +110,7 @@ abstract class HsmBaseTest {
keyOverride = 0,
crlIssuer = null,
crlDistributionUrl = null
))
), hsmUserConfigs)
}
protected fun createHsmSigningServiceConfig(): Parameters {
@ -91,7 +119,7 @@ abstract class HsmBaseTest {
device = "${hsmSimulator.port}@${hsmSimulator.host}",
keySpecifier = 1,
rootKeyStoreFile = rootKeyStoreFile,
rootKeyStorePassword = ROOT_KEYSTORE_PASSWORD,
rootKeyStorePassword = TRUSTSTORE_PASSWORD,
doormanKeyGroup = DOORMAN_CERT_KEY_GROUP,
networkMapKeyGroup = NETWORK_MAP_CERT_KEY_GROUP,
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>()
whenever(inputReader.readLine()).thenReturn(hsmSimulator.cryptoUserCredentials().username)
whenever(inputReader.readPassword(any())).thenReturn(hsmSimulator.cryptoUserCredentials().password)
whenever(inputReader.readLine()).thenReturn(username)
whenever(inputReader.readPassword(any())).thenReturn(password)
return inputReader
}

View File

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

View File

@ -31,7 +31,7 @@ class HsmSigningServiceTest : HsmBaseTest() {
@Before
fun setUp() {
loadOrCreateKeyStore(rootKeyStoreFile, ROOT_KEYSTORE_PASSWORD)
loadOrCreateKeyStore(rootKeyStoreFile, TRUSTSTORE_PASSWORD)
}
@Test