mirror of
https://github.com/corda/corda.git
synced 2024-12-30 01:39:04 +00:00
Fix the command line notary demos (#875)
* The fancy classloader setup in Cordform.loadCordformDefinition is defeated by certificates in 2 ways ** Class cast when creating a cert (via TestConstants) in a CordformDefinition ** Some issue when persisting a cert in ServiceIdentityGenerator * This PR is a quickfix to get the demos working again * Proper fix (not this PR) is to work out why it's not enough for eddsa to be in the project runtime classpath - if it can be removed from the gradle environment that ought to properly fix the above problems
This commit is contained in:
parent
8aa325d9f7
commit
ef74a0a618
@ -23,8 +23,8 @@ val DUMMY_KEY_2: KeyPair by lazy { generateKeyPair() }
|
||||
|
||||
val DUMMY_NOTARY_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(20)) }
|
||||
/** Dummy notary identity for tests and simulations */
|
||||
val DUMMY_NOTARY_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH"), DUMMY_NOTARY_KEY.public)
|
||||
val DUMMY_NOTARY: Party get() = DUMMY_NOTARY_IDENTITY.party
|
||||
val DUMMY_NOTARY_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(DUMMY_NOTARY)
|
||||
val DUMMY_NOTARY: Party get() = Party(X500Name("CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH"), DUMMY_NOTARY_KEY.public)
|
||||
|
||||
val DUMMY_MAP_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(30)) }
|
||||
/** Dummy network map service identity for tests and simulations */
|
||||
@ -44,13 +44,13 @@ val DUMMY_BANK_C: Party get() = Party(X500Name("CN=Bank C,O=Bank C,L=Tokyo,C=JP"
|
||||
|
||||
val ALICE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(70)) }
|
||||
/** Dummy individual identity for tests and simulations */
|
||||
val ALICE_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Alice Corp,O=Alice Corp,L=Madrid,C=ES"), ALICE_KEY.public)
|
||||
val ALICE: Party get() = ALICE_IDENTITY.party
|
||||
val ALICE_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(ALICE)
|
||||
val ALICE: Party get() = Party(X500Name("CN=Alice Corp,O=Alice Corp,L=Madrid,C=ES"), ALICE_KEY.public)
|
||||
|
||||
val BOB_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(80)) }
|
||||
/** Dummy individual identity for tests and simulations */
|
||||
val BOB_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bob Plc,O=Bob Plc,L=Rome,C=IT"), BOB_KEY.public)
|
||||
val BOB: Party get() = BOB_IDENTITY.party
|
||||
val BOB_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(BOB)
|
||||
val BOB: Party get() = Party(X500Name("CN=Bob Plc,O=Bob Plc,L=Rome,C=IT"), BOB_KEY.public)
|
||||
|
||||
val CHARLIE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(90)) }
|
||||
/** Dummy individual identity for tests and simulations */
|
||||
@ -70,9 +70,11 @@ val DUMMY_CA: CertificateAndKeyPair by lazy {
|
||||
/**
|
||||
* Build a test party with a nonsense certificate authority for testing purposes.
|
||||
*/
|
||||
fun getTestPartyAndCertificate(name: X500Name, publicKey: PublicKey, trustRoot: CertificateAndKeyPair = DUMMY_CA): PartyAndCertificate {
|
||||
fun getTestPartyAndCertificate(name: X500Name, publicKey: PublicKey, trustRoot: CertificateAndKeyPair = DUMMY_CA) = getTestPartyAndCertificate(Party(name, publicKey), trustRoot)
|
||||
|
||||
fun getTestPartyAndCertificate(party: Party, trustRoot: CertificateAndKeyPair = DUMMY_CA): PartyAndCertificate {
|
||||
val certFactory = CertificateFactory.getInstance("X509")
|
||||
val certHolder = X509Utilities.createCertificate(CertificateType.IDENTITY, trustRoot.certificate, trustRoot.keyPair, name, publicKey)
|
||||
val certHolder = X509Utilities.createCertificate(CertificateType.IDENTITY, trustRoot.certificate, trustRoot.keyPair, party.name, party.owningKey)
|
||||
val certPath = certFactory.generateCertPath(listOf(certHolder.cert, trustRoot.certificate.cert))
|
||||
return PartyAndCertificate(name, publicKey, certHolder, certPath)
|
||||
return PartyAndCertificate(party, certHolder, certPath)
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import net.corda.core.crypto.appendToCommonName
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.utilities.ALICE
|
||||
import net.corda.core.utilities.DUMMY_CA
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
import net.corda.flows.NotaryError
|
||||
import net.corda.flows.NotaryException
|
||||
@ -39,9 +38,8 @@ class BFTNotaryServiceTests : NodeBasedTest() {
|
||||
val replicaNames = replicaIds.map { DUMMY_NOTARY.name.appendToCommonName(" $it") }
|
||||
val party = ServiceIdentityGenerator.generateToDisk(
|
||||
replicaNames.map { baseDirectory(it) },
|
||||
DUMMY_CA,
|
||||
serviceType.id,
|
||||
clusterName).party
|
||||
clusterName)
|
||||
val advertisedServices = setOf(ServiceInfo(serviceType, clusterName))
|
||||
val config = mapOf("notaryClusterAddresses" to replicaIds.map { "localhost:${11000 + it * 10}" })
|
||||
return Futures.allAsList(replicaIds.map {
|
||||
|
@ -64,7 +64,6 @@ class P2PMessagingTest : NodeBasedTest() {
|
||||
fun `communicating with a distributed service which the network map node is part of`() {
|
||||
ServiceIdentityGenerator.generateToDisk(
|
||||
listOf(DUMMY_MAP.name, SERVICE_2_NAME).map { baseDirectory(it) },
|
||||
DUMMY_CA,
|
||||
RaftValidatingNotaryService.type.id,
|
||||
DISTRIBUTED_SERVICE_NAME)
|
||||
|
||||
|
@ -23,7 +23,9 @@ import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.DUMMY_CA
|
||||
import net.corda.core.utilities.debug
|
||||
import net.corda.core.utilities.getTestPartyAndCertificate
|
||||
import net.corda.flows.*
|
||||
import net.corda.node.services.*
|
||||
import net.corda.node.services.api.*
|
||||
@ -57,7 +59,6 @@ import net.corda.node.utilities.configureDatabase
|
||||
import net.corda.node.utilities.transaction
|
||||
import org.apache.activemq.artemis.utils.ReusableLatch
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.bouncycastle.cert.X509CertificateHolder
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.slf4j.Logger
|
||||
import rx.Observable
|
||||
@ -215,8 +216,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
|
||||
// Do all of this in a database transaction so anything that might need a connection has one.
|
||||
initialiseDatabasePersistence {
|
||||
val keyStoreWrapper = KeyStoreWrapper(configuration.trustStoreFile, configuration.trustStorePassword)
|
||||
val tokenizableServices = makeServices(keyStoreWrapper)
|
||||
val tokenizableServices = makeServices()
|
||||
|
||||
smm = StateMachineManager(services,
|
||||
checkpointStorage,
|
||||
@ -439,8 +439,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
* Builds node internal, advertised, and plugin services.
|
||||
* Returns a list of tokenizable services to be added to the serialisation context.
|
||||
*/
|
||||
private fun makeServices(keyStoreWrapper: KeyStoreWrapper): MutableList<Any> {
|
||||
val keyStore = keyStoreWrapper.keyStore
|
||||
private fun makeServices(): MutableList<Any> {
|
||||
val storageServices = initialiseStorageService(configuration.baseDirectory)
|
||||
storage = storageServices.first
|
||||
checkpointStorage = storageServices.second
|
||||
@ -778,7 +777,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
// Check that the identity in the config file matches the identity file we have stored to disk.
|
||||
// This is just a sanity check. It shouldn't fail unless the admin has fiddled with the files and messed
|
||||
// things up for us.
|
||||
val myIdentity = pubIdentityFile.readAll().deserialize<PartyAndCertificate>()
|
||||
val myIdentity = pubIdentityFile.readAll().deserialize<Party>()
|
||||
if (myIdentity.name != serviceName)
|
||||
throw ConfigurationException("The legal name in the config file doesn't match the stored identity file:" +
|
||||
"$serviceName vs ${myIdentity.name}")
|
||||
@ -787,7 +786,13 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
if (myIdentity.owningKey !is CompositeKey) { // TODO: Support case where owningKey is a composite key.
|
||||
keyStore.save(serviceName, privateKeyAlias, keyPair)
|
||||
}
|
||||
Pair(myIdentity, keyPair)
|
||||
val partyAndCertificate = getTestPartyAndCertificate(myIdentity)
|
||||
// Sanity check the certificate and path
|
||||
val validatorParameters = PKIXParameters(setOf(TrustAnchor(DUMMY_CA.certificate.cert, null)))
|
||||
val validator = CertPathValidator.getInstance("PKIX")
|
||||
validatorParameters.isRevocationEnabled = false
|
||||
validator.validate(partyAndCertificate.certPath, validatorParameters) as PKIXCertPathValidatorResult
|
||||
Pair(partyAndCertificate, keyPair)
|
||||
} else {
|
||||
val clientCertPath = keyStore.keyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA)
|
||||
val clientCA = keyStore.certificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA)!!
|
||||
|
@ -1,7 +1,9 @@
|
||||
package net.corda.node.utilities
|
||||
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.crypto.CompositeKey
|
||||
import net.corda.core.crypto.X509Utilities
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.serialization.storageKryo
|
||||
import net.corda.core.utilities.loggerFor
|
||||
@ -9,7 +11,6 @@ import net.corda.core.utilities.trace
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.security.cert.*
|
||||
|
||||
object ServiceIdentityGenerator {
|
||||
private val log = loggerFor<ServiceIdentityGenerator>()
|
||||
@ -20,35 +21,23 @@ object ServiceIdentityGenerator {
|
||||
* This method should be called *before* any of the nodes are started.
|
||||
*
|
||||
* @param dirs List of node directories to place the generated identity and key pairs in.
|
||||
* @param serviceCa Certificate authority to use when signing identity certificates.
|
||||
* @param serviceId The service id of the distributed service.
|
||||
* @param serviceName The legal name of the distributed service.
|
||||
* @param threshold The threshold for the generated group [CompositeKey].
|
||||
*/
|
||||
// TODO: This needs to write out to the key store, not just files on disk
|
||||
fun generateToDisk(dirs: List<Path>,
|
||||
serviceCa: CertificateAndKeyPair,
|
||||
serviceId: String,
|
||||
serviceName: X500Name,
|
||||
threshold: Int = 1): PartyAndCertificate {
|
||||
threshold: Int = 1): Party {
|
||||
log.trace { "Generating a group identity \"serviceName\" for nodes: ${dirs.joinToString()}" }
|
||||
val keyPairs = (1..dirs.size).map { generateKeyPair() }
|
||||
val notaryKey = CompositeKey.Builder().addKeys(keyPairs.map { it.public }).build(threshold)
|
||||
val certFactory = CertificateFactory.getInstance("X509")
|
||||
val notaryCert = X509Utilities.createCertificate(CertificateType.IDENTITY, serviceCa.certificate,
|
||||
serviceCa.keyPair, serviceName, notaryKey)
|
||||
val notaryCertPath = certFactory.generateCertPath(listOf(notaryCert.cert, serviceCa.certificate.cert))
|
||||
val notaryParty = PartyAndCertificate(serviceName, notaryKey, notaryCert, notaryCertPath)
|
||||
// Avoid adding complexity! This class is a hack that needs to stay runnable in the gradle environment.
|
||||
val notaryParty = Party(serviceName, notaryKey)
|
||||
val notaryPartyBytes = notaryParty.serialize()
|
||||
val privateKeyFile = "$serviceId-private-key"
|
||||
val publicKeyFile = "$serviceId-public"
|
||||
|
||||
// Sanity check the certificate and path
|
||||
val validatorParameters = PKIXParameters(setOf(TrustAnchor(serviceCa.certificate.cert, null)))
|
||||
val validator = CertPathValidator.getInstance("PKIX")
|
||||
validatorParameters.isRevocationEnabled = false
|
||||
validator.validate(notaryCertPath, validatorParameters) as PKIXCertPathValidatorResult
|
||||
|
||||
keyPairs.zip(dirs) { keyPair, dir ->
|
||||
Files.createDirectories(dir)
|
||||
notaryPartyBytes.writeToFile(dir.resolve(publicKeyFile))
|
||||
|
@ -5,7 +5,6 @@ import net.corda.core.div
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.utilities.ALICE
|
||||
import net.corda.core.utilities.BOB
|
||||
import net.corda.core.utilities.DUMMY_CA
|
||||
import net.corda.demorun.util.*
|
||||
import net.corda.demorun.runNodes
|
||||
import net.corda.node.services.transactions.BFTNonValidatingNotaryService
|
||||
@ -66,6 +65,6 @@ object BFTNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", not
|
||||
}
|
||||
|
||||
override fun setup(context: CordformContext) {
|
||||
ServiceIdentityGenerator.generateToDisk(notaryNames.map { context.baseDirectory(it) }, DUMMY_CA, advertisedService.type.id, clusterName, minCorrectReplicas(clusterSize))
|
||||
ServiceIdentityGenerator.generateToDisk(notaryNames.map { context.baseDirectory(it) }, advertisedService.type.id, clusterName, minCorrectReplicas(clusterSize))
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import net.corda.core.div
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.utilities.ALICE
|
||||
import net.corda.core.utilities.BOB
|
||||
import net.corda.core.utilities.DUMMY_CA
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
import net.corda.demorun.util.*
|
||||
import net.corda.node.services.transactions.RaftValidatingNotaryService
|
||||
@ -66,6 +65,6 @@ object RaftNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", no
|
||||
}
|
||||
|
||||
override fun setup(context: CordformContext) {
|
||||
ServiceIdentityGenerator.generateToDisk(notaryNames.map { context.baseDirectory(it) }, DUMMY_CA, advertisedService.type.id, clusterName)
|
||||
ServiceIdentityGenerator.generateToDisk(notaryNames.map { context.baseDirectory(it) }, advertisedService.type.id, clusterName)
|
||||
}
|
||||
}
|
||||
|
@ -613,7 +613,7 @@ class DriverDSL(
|
||||
): ListenableFuture<Pair<Party, List<NodeHandle>>> {
|
||||
val nodeNames = (0 until clusterSize).map { DUMMY_NOTARY.name.appendToCommonName(" $it") }
|
||||
val paths = nodeNames.map { baseDirectory(it) }
|
||||
ServiceIdentityGenerator.generateToDisk(paths, DUMMY_CA, type.id, notaryName)
|
||||
ServiceIdentityGenerator.generateToDisk(paths, type.id, notaryName)
|
||||
val advertisedServices = setOf(ServiceInfo(type, notaryName))
|
||||
val notaryClusterAddress = portAllocation.nextHostAndPort()
|
||||
|
||||
|
@ -9,7 +9,6 @@ import net.corda.core.crypto.appendToCommonName
|
||||
import net.corda.core.crypto.commonName
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.node.services.ServiceType
|
||||
import net.corda.core.utilities.DUMMY_CA
|
||||
import net.corda.core.utilities.DUMMY_MAP
|
||||
import net.corda.core.utilities.WHITESPACE
|
||||
import net.corda.node.internal.Node
|
||||
@ -113,7 +112,6 @@ abstract class NodeBasedTest {
|
||||
serviceType: ServiceType = RaftValidatingNotaryService.type): ListenableFuture<List<Node>> {
|
||||
ServiceIdentityGenerator.generateToDisk(
|
||||
(0 until clusterSize).map { baseDirectory(notaryName.appendToCommonName("-$it")) },
|
||||
DUMMY_CA,
|
||||
serviceType.id,
|
||||
notaryName)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user