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:
Andrzej Cichocki
2017-06-21 10:25:11 +01:00
committed by GitHub
parent 8aa325d9f7
commit ef74a0a618
9 changed files with 34 additions and 45 deletions

View File

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

View File

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

View File

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

View File

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