From dc8d232480de3ad3cb2bf85f5ee32e626aa228bf Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Tue, 15 Aug 2017 18:37:08 +0100 Subject: [PATCH] Creating a PartyAndCertificate only requires a CertPath --- .../net/corda/core/crypto/X500NameUtils.kt | 3 +- .../net/corda/core/identity/AbstractParty.kt | 3 +- .../net/corda/core/identity/AnonymousParty.kt | 7 +- .../kotlin/net/corda/core/identity/Party.kt | 11 +-- .../core/identity/PartyAndCertificate.kt | 51 +++++------- .../net/corda/core/internal/InternalUtils.kt | 4 + .../kotlin/net/corda/core/node/NodeInfo.kt | 15 ++-- .../core/node/services/IdentityService.kt | 9 ++- .../core/identity/PartyAndCertificateTest.kt | 26 ++++++ .../serialization/DefaultKryoCustomizer.kt | 39 +++++---- .../net/corda/node/internal/AbstractNode.kt | 81 +++++++++---------- .../kotlin/net/corda/node/internal/Node.kt | 5 +- .../identity/InMemoryIdentityService.kt | 27 +++---- .../net/corda/node/services/keys/KMSUtils.kt | 6 +- .../messaging/ArtemisMessagingServer.kt | 12 +-- .../network/PersistentNetworkMapService.kt | 6 +- .../corda/node/utilities/KeyStoreUtilities.kt | 11 ++- .../network/InMemoryIdentityServiceTests.kt | 10 +-- .../NetworkisRegistrationHelperTest.kt | 6 +- .../flow/CommercialPaperIssueFlow.kt | 4 +- .../kotlin/net/corda/testing/CoreTestUtils.kt | 2 +- .../kotlin/net/corda/testing/node/MockNode.kt | 2 +- 22 files changed, 172 insertions(+), 168 deletions(-) create mode 100644 core/src/test/kotlin/net/corda/core/identity/PartyAndCertificateTest.kt diff --git a/core/src/main/kotlin/net/corda/core/crypto/X500NameUtils.kt b/core/src/main/kotlin/net/corda/core/crypto/X500NameUtils.kt index 0043988ba4..6edd82ca93 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/X500NameUtils.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/X500NameUtils.kt @@ -1,6 +1,7 @@ @file:JvmName("X500NameUtils") package net.corda.core.crypto +import net.corda.core.internal.toX509CertHolder import org.bouncycastle.asn1.ASN1Encodable import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500NameBuilder @@ -57,7 +58,7 @@ val X500Name.locationOrNull: String? get() = try { } catch (e: Exception) { null } -val X509Certificate.subject: X500Name get() = X509CertificateHolder(encoded).subject +val X509Certificate.subject: X500Name get() = toX509CertHolder().subject val X509CertificateHolder.cert: X509Certificate get() = JcaX509CertificateConverter().getCertificate(this) /** diff --git a/core/src/main/kotlin/net/corda/core/identity/AbstractParty.kt b/core/src/main/kotlin/net/corda/core/identity/AbstractParty.kt index 7dc89ae4a5..b549f33e11 100644 --- a/core/src/main/kotlin/net/corda/core/identity/AbstractParty.kt +++ b/core/src/main/kotlin/net/corda/core/identity/AbstractParty.kt @@ -13,8 +13,7 @@ import java.security.PublicKey @CordaSerializable abstract class AbstractParty(val owningKey: PublicKey) { /** Anonymised parties do not include any detail apart from owning key, so equality is dependent solely on the key */ - override fun equals(other: Any?): Boolean = other is AbstractParty && this.owningKey == other.owningKey - + override fun equals(other: Any?): Boolean = other === this || other is AbstractParty && other.owningKey == owningKey override fun hashCode(): Int = owningKey.hashCode() abstract fun nameOrNull(): X500Name? diff --git a/core/src/main/kotlin/net/corda/core/identity/AnonymousParty.kt b/core/src/main/kotlin/net/corda/core/identity/AnonymousParty.kt index b2264a1c6f..ed6e5b3707 100644 --- a/core/src/main/kotlin/net/corda/core/identity/AnonymousParty.kt +++ b/core/src/main/kotlin/net/corda/core/identity/AnonymousParty.kt @@ -1,7 +1,6 @@ package net.corda.core.identity import net.corda.core.contracts.PartyAndReference -import net.corda.core.crypto.toBase58String import net.corda.core.crypto.toStringShort import net.corda.core.utilities.OpaqueBytes import org.bouncycastle.asn1.x500.X500Name @@ -12,11 +11,7 @@ import java.security.PublicKey * information such as name. It is intended to represent a party on the distributed ledger. */ class AnonymousParty(owningKey: PublicKey) : AbstractParty(owningKey) { - // Use the key as the bulk of the toString(), but include a human readable identifier as well, so that [Party] - // can put in the key and actual name - override fun toString() = "${owningKey.toStringShort()} " - override fun nameOrNull(): X500Name? = null - override fun ref(bytes: OpaqueBytes): PartyAndReference = PartyAndReference(this, bytes) + override fun toString() = "Anonymous(${owningKey.toStringShort()})" } \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/identity/Party.kt b/core/src/main/kotlin/net/corda/core/identity/Party.kt index a2f301be75..5652fc2688 100644 --- a/core/src/main/kotlin/net/corda/core/identity/Party.kt +++ b/core/src/main/kotlin/net/corda/core/identity/Party.kt @@ -1,9 +1,11 @@ package net.corda.core.identity import net.corda.core.contracts.PartyAndReference -import net.corda.core.crypto.CertificateAndKeyPair +import net.corda.core.crypto.Crypto +import net.corda.core.crypto.composite.CompositeKey import net.corda.core.utilities.OpaqueBytes import org.bouncycastle.asn1.x500.X500Name +import org.bouncycastle.cert.X509CertificateHolder import java.security.PublicKey /** @@ -26,10 +28,9 @@ import java.security.PublicKey * @see CompositeKey */ class Party(val name: X500Name, owningKey: PublicKey) : AbstractParty(owningKey) { - constructor(certAndKey: CertificateAndKeyPair) : this(certAndKey.certificate.subject, certAndKey.keyPair.public) - override fun toString() = name.toString() - override fun nameOrNull(): X500Name? = name - + constructor(certificate: X509CertificateHolder) : this(certificate.subject, Crypto.toSupportedPublicKey(certificate.subjectPublicKeyInfo)) + override fun nameOrNull(): X500Name = name fun anonymise(): AnonymousParty = AnonymousParty(owningKey) override fun ref(bytes: OpaqueBytes): PartyAndReference = PartyAndReference(this, bytes) + override fun toString() = name.toString() } diff --git a/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt b/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt index 557c26d7ee..e6f972798a 100644 --- a/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt +++ b/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt @@ -1,49 +1,42 @@ package net.corda.core.identity -import net.corda.core.serialization.CordaSerializable +import net.corda.core.internal.toX509CertHolder import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509CertificateHolder import java.security.PublicKey import java.security.cert.* -import java.util.* /** * A full party plus the X.509 certificate and path linking the party back to a trust root. Equality of * [PartyAndCertificate] instances is based on the party only, as certificate and path are data associated with the party, - * not part of the identifier themselves. While party and certificate can both be derived from the certificate path, - * this class exists in order to ensure the implementation classes of certificates and party public keys are kept stable. + * not part of the identifier themselves. */ -@CordaSerializable -data class PartyAndCertificate(val party: Party, - val certificate: X509CertificateHolder, - val certPath: CertPath) { - constructor(name: X500Name, owningKey: PublicKey, certificate: X509CertificateHolder, certPath: CertPath) : this(Party(name, owningKey), certificate, certPath) - val name: X500Name - get() = party.name - val owningKey: PublicKey - get() = party.owningKey - - override fun equals(other: Any?): Boolean { - return if (other is PartyAndCertificate) - party == other.party - else - false +//TODO Is VerifiableIdentity a better name? +class PartyAndCertificate(val certPath: CertPath) { + @Transient val certificate: X509CertificateHolder + init { + require(certPath.type == "X.509") { "Only X.509 certificates supported" } + val certs = certPath.certificates + require(certs.size >= 2) { "Certificate path must at least include subject and issuing certificates" } + certificate = certs[0].toX509CertHolder() } + @Transient val party: Party = Party(certificate) + + val owningKey: PublicKey get() = party.owningKey + val name: X500Name get() = party.name + + operator fun component1(): Party = party + operator fun component2(): X509CertificateHolder = certificate + + override fun equals(other: Any?): Boolean = other === this || other is PartyAndCertificate && other.party == party override fun hashCode(): Int = party.hashCode() override fun toString(): String = party.toString() - /** - * Verify that the given certificate path is valid and leads to the owning key of the party. - */ + /** Verify the certificate path is valid. */ fun verify(trustAnchor: TrustAnchor): PKIXCertPathValidatorResult { - require(certPath.certificates.first() is X509Certificate) { "Subject certificate must be an X.509 certificate" } - require(Arrays.equals(party.owningKey.encoded, certificate.subjectPublicKeyInfo.encoded)) { "Certificate public key must match party owning key" } - require(Arrays.equals(certPath.certificates.first().encoded, certificate.encoded)) { "Certificate path must link to certificate" } - - val validatorParameters = PKIXParameters(setOf(trustAnchor)) + val parameters = PKIXParameters(setOf(trustAnchor)).apply { isRevocationEnabled = false } val validator = CertPathValidator.getInstance("PKIX") - validatorParameters.isRevocationEnabled = false - return validator.validate(certPath, validatorParameters) as PKIXCertPathValidatorResult + return validator.validate(certPath, parameters) as PKIXCertPathValidatorResult } } diff --git a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt index e0d9f37580..b362339540 100644 --- a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt @@ -2,6 +2,7 @@ package net.corda.core.internal import net.corda.core.crypto.SecureHash import net.corda.core.crypto.sha256 +import org.bouncycastle.cert.X509CertificateHolder import org.slf4j.Logger import rx.Observable import rx.Observer @@ -165,6 +166,9 @@ fun logElapsedTime(label: String, logger: Logger? = null, body: () -> T): T } } +fun java.security.cert.Certificate.toX509CertHolder() = X509CertificateHolder(encoded) +fun javax.security.cert.Certificate.toX509CertHolder() = X509CertificateHolder(encoded) + /** Convert a [ByteArrayOutputStream] to [InputStreamAndHash]. */ fun ByteArrayOutputStream.toInputStreamAndHash(): InputStreamAndHash { val bytes = toByteArray() diff --git a/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt b/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt index 7b71cdcde2..d7f30a4f50 100644 --- a/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt +++ b/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt @@ -24,16 +24,17 @@ data class NodeInfo(val addresses: List, val legalIdentityAndCert: PartyAndCertificate, //TODO This field will be removed in future PR which gets rid of services. val legalIdentitiesAndCerts: NonEmptySet, val platformVersion: Int, - var advertisedServices: List = emptyList(), + val advertisedServices: List = emptyList(), val worldMapLocation: WorldMapLocation? = null) { init { - require(advertisedServices.none { it.identity == legalIdentityAndCert }) { "Service identities must be different from node legal identity" } + require(advertisedServices.none { it.identity == legalIdentityAndCert }) { + "Service identities must be different from node legal identity" + } } - val legalIdentity: Party - get() = legalIdentityAndCert.party - val notaryIdentity: Party - get() = advertisedServices.single { it.info.type.isNotary() }.identity.party + + val legalIdentity: Party get() = legalIdentityAndCert.party + val notaryIdentity: Party get() = advertisedServices.single { it.info.type.isNotary() }.identity.party fun serviceIdentities(type: ServiceType): List { - return advertisedServices.filter { it.info.type.isSubTypeOf(type) }.map { it.identity.party } + return advertisedServices.mapNotNull { if (it.info.type.isSubTypeOf(type)) it.identity.party else null } } } diff --git a/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt b/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt index 008d114ebc..916ef6dbe6 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt @@ -1,7 +1,10 @@ package net.corda.core.node.services import net.corda.core.contracts.PartyAndReference -import net.corda.core.identity.* +import net.corda.core.identity.AbstractParty +import net.corda.core.identity.AnonymousParty +import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509CertificateHolder import java.security.InvalidAlgorithmParameterException @@ -114,6 +117,6 @@ interface IdentityService { * @param exactMatch If true, a case sensitive match is done against each component of each X.500 name. */ fun partiesFromName(query: String, exactMatch: Boolean): Set - - class UnknownAnonymousPartyException(msg: String) : Exception(msg) } + +class UnknownAnonymousPartyException(msg: String) : Exception(msg) diff --git a/core/src/test/kotlin/net/corda/core/identity/PartyAndCertificateTest.kt b/core/src/test/kotlin/net/corda/core/identity/PartyAndCertificateTest.kt new file mode 100644 index 0000000000..f6341d9253 --- /dev/null +++ b/core/src/test/kotlin/net/corda/core/identity/PartyAndCertificateTest.kt @@ -0,0 +1,26 @@ +package net.corda.core.identity + +import net.corda.core.crypto.entropyToKeyPair +import net.corda.core.serialization.deserialize +import net.corda.core.serialization.serialize +import net.corda.testing.getTestPartyAndCertificate +import net.corda.testing.withTestSerialization +import org.assertj.core.api.Assertions.assertThat +import org.bouncycastle.asn1.x500.X500Name +import org.junit.Test +import java.math.BigInteger + +class PartyAndCertificateTest { + @Test + fun `kryo serialisation`() { + withTestSerialization { + val original = getTestPartyAndCertificate(Party( + X500Name("CN=Test Corp,O=Test Corp,L=Madrid,C=ES"), + entropyToKeyPair(BigInteger.valueOf(83)).public)) + val copy = original.serialize().deserialize() + assertThat(copy).isEqualTo(original).isNotSameAs(original) + assertThat(copy.certPath).isEqualTo(original.certPath) + assertThat(copy.certificate).isEqualTo(original.certificate) + } + } +} diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/DefaultKryoCustomizer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/DefaultKryoCustomizer.kt index 5112ea6a33..f67d41841d 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/DefaultKryoCustomizer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/DefaultKryoCustomizer.kt @@ -12,6 +12,7 @@ import de.javakaffee.kryoserializers.BitSetSerializer import de.javakaffee.kryoserializers.UnmodifiableCollectionsSerializer import de.javakaffee.kryoserializers.guava.* import net.corda.core.crypto.composite.CompositeKey +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.CordaPluginRegistry import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializedBytes @@ -59,6 +60,12 @@ object DefaultKryoCustomizer { instantiatorStrategy = CustomInstantiatorStrategy() + // Required for HashCheckingStream (de)serialization. + // Note that return type should be specifically set to InputStream, otherwise it may not work, i.e. val aStream : InputStream = HashCheckingStream(...). + addDefaultSerializer(InputStream::class.java, InputStreamSerializer) + addDefaultSerializer(SerializeAsToken::class.java, SerializeAsTokenSerializer()) + addDefaultSerializer(Logger::class.java, LoggerSerializer) + // WARNING: reordering the registrations here will cause a change in the serialized form, since classes // with custom serializers get written as registration ids. This will break backwards-compatibility. // Please add any new registrations to the end. @@ -68,50 +75,31 @@ object DefaultKryoCustomizer { register(SignedTransaction::class.java, SignedTransactionSerializer) register(WireTransaction::class.java, WireTransactionSerializer) register(SerializedBytes::class.java, SerializedBytesSerializer) - UnmodifiableCollectionsSerializer.registerSerializers(this) ImmutableListSerializer.registerSerializers(this) ImmutableSetSerializer.registerSerializers(this) ImmutableSortedSetSerializer.registerSerializers(this) ImmutableMapSerializer.registerSerializers(this) ImmutableMultimapSerializer.registerSerializers(this) - // InputStream subclasses whitelisting, required for attachments. register(BufferedInputStream::class.java, InputStreamSerializer) register(Class.forName("sun.net.www.protocol.jar.JarURLConnection\$JarURLInputStream"), InputStreamSerializer) - noReferencesWithin() - register(ECPublicKeyImpl::class.java, ECPublicKeyImplSerializer) register(EdDSAPublicKey::class.java, Ed25519PublicKeySerializer) register(EdDSAPrivateKey::class.java, Ed25519PrivateKeySerializer) - - // Using a custom serializer for compactness - register(CompositeKey::class.java, CompositeKeySerializer) - + register(CompositeKey::class.java, CompositeKeySerializer) // Using a custom serializer for compactness // Exceptions. We don't bother sending the stack traces as the client will fill in its own anyway. register(Array::class, read = { _, _ -> emptyArray() }, write = { _, _, _ -> }) - // This ensures a NonEmptySetSerializer is constructed with an initial value. register(NonEmptySet::class.java, NonEmptySetSerializer) - - addDefaultSerializer(SerializeAsToken::class.java, SerializeAsTokenSerializer()) - register(BitSet::class.java, BitSetSerializer()) register(Class::class.java, ClassSerializer) - - addDefaultSerializer(Logger::class.java, LoggerSerializer) - register(FileInputStream::class.java, InputStreamSerializer) - // Required for HashCheckingStream (de)serialization. - // Note that return type should be specifically set to InputStream, otherwise it may not work, i.e. val aStream : InputStream = HashCheckingStream(...). - addDefaultSerializer(InputStream::class.java, InputStreamSerializer) - register(CertPath::class.java, CertPathSerializer) register(X509CertPath::class.java, CertPathSerializer) register(X500Name::class.java, X500NameSerializer) register(X509CertificateHolder::class.java, X509CertificateSerializer) - register(BCECPrivateKey::class.java, PrivateKeySerializer) register(BCECPublicKey::class.java, PublicKeySerializer) register(BCRSAPrivateCrtKey::class.java, PrivateKeySerializer) @@ -119,8 +107,8 @@ object DefaultKryoCustomizer { register(BCSphincs256PrivateKey::class.java, PrivateKeySerializer) register(BCSphincs256PublicKey::class.java, PublicKeySerializer) register(sun.security.ec.ECPublicKeyImpl::class.java, PublicKeySerializer) - register(NotaryChangeWireTransaction::class.java, NotaryChangeWireTransactionSerializer) + register(PartyAndCertificate::class.java, PartyAndCertificateSerializer) val customization = KryoSerializationCustomization(this) pluginRegistries.forEach { it.customizeSerialization(customization) } @@ -139,6 +127,15 @@ object DefaultKryoCustomizer { } } + private object PartyAndCertificateSerializer : Serializer() { + override fun write(kryo: Kryo, output: Output, obj: PartyAndCertificate) { + kryo.writeClassAndObject(output, obj.certPath) + } + override fun read(kryo: Kryo, input: Input, type: Class): PartyAndCertificate { + return PartyAndCertificate(kryo.readClassAndObject(input) as CertPath) + } + } + private object NonEmptySetSerializer : Serializer>() { override fun write(kryo: Kryo, output: Output, obj: NonEmptySet) { // Write out the contents as normal diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index b734859b2c..914be297d7 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -2,6 +2,7 @@ package net.corda.node.internal import com.codahale.metrics.MetricRegistry import com.google.common.annotations.VisibleForTesting +import com.google.common.collect.Lists import com.google.common.collect.MutableClassToInstanceMap import com.google.common.util.concurrent.MoreExecutors import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner @@ -66,7 +67,6 @@ import net.corda.node.utilities.* import net.corda.node.utilities.AddOrRemove.ADD import org.apache.activemq.artemis.utils.ReusableLatch import org.bouncycastle.asn1.x500.X500Name -import org.bouncycastle.cert.X509CertificateHolder import org.slf4j.Logger import rx.Observable import java.io.IOException @@ -88,6 +88,9 @@ import java.util.concurrent.ExecutorService import java.util.concurrent.TimeUnit.SECONDS import java.util.stream.Collectors.toList import kotlin.collections.ArrayList +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.collections.set import kotlin.reflect.KClass import net.corda.core.crypto.generateKeyPair as cryptoGenerateKeyPair @@ -417,8 +420,9 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, checkpointStorage = DBCheckpointStorage() _services = ServiceHubInternalImpl() attachments = NodeAttachmentService(configuration.dataSourceProperties, services.monitoringService.metrics, configuration.database) - network = makeMessagingService() - info = makeInfo() + val legalIdentity = obtainIdentity("identity", configuration.myLegalName) + network = makeMessagingService(legalIdentity) + info = makeInfo(legalIdentity) val tokenizableServices = mutableListOf(attachments, network, services.vaultService, services.vaultQueryService, services.keyManagementService, services.identityService, platformClock, services.schedulerService) @@ -486,12 +490,11 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, HibernateObserver(services.vaultService.rawUpdates, HibernateConfiguration(services.schemaService, configuration.database ?: Properties(), {services.identityService})) } - private fun makeInfo(): NodeInfo { + private fun makeInfo(legalIdentity: PartyAndCertificate): NodeInfo { val advertisedServiceEntries = makeServiceEntries() - val legalIdentity = obtainLegalIdentity() - val allIdentitiesSet = (advertisedServiceEntries.map { it.identity } + legalIdentity).toNonEmptySet() + val allIdentities = (advertisedServiceEntries.map { it.identity } + legalIdentity).toNonEmptySet() val addresses = myAddresses() // TODO There is no support for multiple IP addresses yet. - return NodeInfo(addresses, legalIdentity, allIdentitiesSet, platformVersion, advertisedServiceEntries, findMyLocation()) + return NodeInfo(addresses, legalIdentity, allIdentities, platformVersion, advertisedServiceEntries, findMyLocation()) } /** @@ -502,7 +505,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, return advertisedServices.map { val serviceId = it.type.id val serviceName = it.name ?: X500Name("${configuration.myLegalName},OU=$serviceId") - val identity = obtainKeyPair(serviceId, serviceName).first + val identity = obtainIdentity(serviceId, serviceName) ServiceEntry(it, identity) } } @@ -613,8 +616,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val instant = platformClock.instant() val expires = instant + NetworkMapService.DEFAULT_EXPIRATION_PERIOD val reg = NodeRegistration(info, instant.toEpochMilli(), ADD, expires) - val legalIdentityKey = obtainLegalIdentityKey() - val request = RegistrationRequest(reg.toWire(services.keyManagementService, legalIdentityKey.public), network.myAddress) + val request = RegistrationRequest(reg.toWire(services.keyManagementService, info.legalIdentityAndCert.owningKey), network.myAddress) return network.sendRequest(NetworkMapService.REGISTER_TOPIC, request, networkMapAddress) } @@ -680,15 +682,11 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, runOnStop.clear() } - protected abstract fun makeMessagingService(): MessagingService + protected abstract fun makeMessagingService(legalIdentity: PartyAndCertificate): MessagingService protected abstract fun startMessagingService(rpcOps: RPCOps) - protected fun obtainLegalIdentity(): PartyAndCertificate = identityKeyPair.first - protected fun obtainLegalIdentityKey(): KeyPair = identityKeyPair.second - private val identityKeyPair by lazy { obtainKeyPair("identity", configuration.myLegalName) } - - private fun obtainKeyPair(serviceId: String, serviceName: X500Name): Pair { + private fun obtainIdentity(id: String, name: X500Name): PartyAndCertificate { // Load the private identity key, creating it if necessary. The identity key is a long term well known key that // is distributed to other peers and we use it (or a key signed by it) when we need to do something // "permissioned". The identity file is what gets distributed and contains the node's legal name along with @@ -697,50 +695,52 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, // TODO: Integrate with Key management service? val keyStore = KeyStoreWrapper(configuration.nodeKeystore, configuration.keyStorePassword) - val privateKeyAlias = "$serviceId-private-key" - val compositeKeyAlias = "$serviceId-composite-key" + val privateKeyAlias = "$id-private-key" + val compositeKeyAlias = "$id-composite-key" if (!keyStore.containsAlias(privateKeyAlias)) { val privKeyFile = configuration.baseDirectory / privateKeyAlias - val pubIdentityFile = configuration.baseDirectory / "$serviceId-public" + val pubIdentityFile = configuration.baseDirectory / "$id-public" val compositeKeyFile = configuration.baseDirectory / compositeKeyAlias // TODO: Remove use of [ServiceIdentityGenerator.generateToDisk]. // Get keys from key file. // TODO: this is here to smooth out the key storage transition, remove this migration in future release. if (privKeyFile.exists()) { - migrateKeysFromFile(keyStore, serviceName, pubIdentityFile, privKeyFile, compositeKeyFile, privateKeyAlias, compositeKeyAlias) + migrateKeysFromFile(keyStore, name, pubIdentityFile, privKeyFile, compositeKeyFile, privateKeyAlias, compositeKeyAlias) } else { - log.info("$privateKeyAlias not found in keystore ${configuration.nodeKeystore}, generating fresh key!") - keyStore.saveNewKeyPair(serviceName, privateKeyAlias, generateKeyPair()) + log.info("$privateKeyAlias not found in key store ${configuration.nodeKeystore}, generating fresh key!") + keyStore.saveNewKeyPair(name, privateKeyAlias, generateKeyPair()) } } - val (cert, keys) = keyStore.certificateAndKeyPair(privateKeyAlias) - // Get keys from keystore. - val loadedServiceName = cert.subject - if (loadedServiceName != serviceName) - throw ConfigurationException("The legal name in the config file doesn't match the stored identity keystore:$serviceName vs $loadedServiceName") + val (x509Cert, keys) = keyStore.certificateAndKeyPair(privateKeyAlias) - // Use composite key instead if exists // TODO: Use configuration to indicate composite key should be used instead of public key for the identity. - val (keyPair, certs) = if (keyStore.containsAlias(compositeKeyAlias)) { - val compositeKey = Crypto.toSupportedPublicKey(keyStore.getCertificate(compositeKeyAlias).publicKey) - val compositeKeyCert = keyStore.getCertificate(compositeKeyAlias) + val certificates = if (keyStore.containsAlias(compositeKeyAlias)) { + // Use composite key instead if it exists + val certificate = keyStore.getCertificate(compositeKeyAlias) // We have to create the certificate chain for the composite key manually, this is because in order to store - // the chain in keystore we need a private key, however there are no corresponding private key for composite key. - Pair(KeyPair(compositeKey, keys.private), listOf(compositeKeyCert, *keyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA))) + // the chain in key store we need a private key, however there is no corresponding private key for the composite key. + Lists.asList(certificate, keyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA)) } else { - Pair(keys, keyStore.getCertificateChain(privateKeyAlias).toList()) + keyStore.getCertificateChain(privateKeyAlias).let { + check(it[0].toX509CertHolder() == x509Cert) { "Certificates from key store do not line up!" } + it.asList() + } } - val certPath = CertificateFactory.getInstance("X509").generateCertPath(certs) + + val subject = certificates[0].toX509CertHolder().subject + if (subject != name) + throw ConfigurationException("The name for $id doesn't match what's in the key store: $name vs $subject") + partyKeys += keys - return Pair(PartyAndCertificate(loadedServiceName, keyPair.public, X509CertificateHolder(certs.first().encoded), certPath), keyPair) + return PartyAndCertificate(CertificateFactory.getInstance("X509").generateCertPath(certificates)) } private fun migrateKeysFromFile(keyStore: KeyStoreWrapper, serviceName: X500Name, pubKeyFile: Path, privKeyFile: Path, compositeKeyFile:Path, privateKeyAlias: String, compositeKeyAlias: String) { - log.info("Migrating $privateKeyAlias from file to keystore...") + log.info("Migrating $privateKeyAlias from file to key store...") // Check that the identity in the config file matches the identity file we have stored to disk. // Load the private key. val publicKey = Crypto.decodePublicKey(pubKeyFile.readAll()) @@ -753,13 +753,6 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, log.info("Finish migrating $privateKeyAlias from file to keystore.") } - private fun getTestPartyAndCertificate(party: Party, trustRoot: CertificateAndKeyPair): PartyAndCertificate { - val certFactory = CertificateFactory.getInstance("X509") - 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(party, certHolder, certPath) - } - protected open fun generateKeyPair() = cryptoGenerateKeyPair() private inner class ServiceHubInternalImpl : ServiceHubInternal, SingletonSerializeAsToken() { diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt index a00f5ff2d2..7d8fdda207 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -2,6 +2,7 @@ package net.corda.node.internal import com.codahale.metrics.JmxReporter import net.corda.core.concurrent.CordaFuture +import net.corda.core.identity.PartyAndCertificate import net.corda.core.internal.concurrent.doneFuture import net.corda.core.internal.concurrent.flatMap import net.corda.core.internal.concurrent.openFuture @@ -133,7 +134,7 @@ open class Node(override val configuration: FullNodeConfiguration, private lateinit var userService: RPCUserService - override fun makeMessagingService(): MessagingService { + override fun makeMessagingService(legalIdentity: PartyAndCertificate): MessagingService { userService = RPCUserServiceImpl(configuration.rpcUsers) val (serverAddress, advertisedAddress) = with(configuration) { @@ -147,7 +148,7 @@ open class Node(override val configuration: FullNodeConfiguration, printBasicNodeInfo("Incoming connection address", advertisedAddress.toString()) - val myIdentityOrNullIfNetworkMapService = if (networkMapAddress != null) obtainLegalIdentity().owningKey else null + val myIdentityOrNullIfNetworkMapService = if (networkMapAddress != null) legalIdentity.owningKey else null return NodeMessagingClient( configuration, versionInfo, diff --git a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt index a19ae3698a..80812edd1e 100644 --- a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt +++ b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt @@ -7,7 +7,9 @@ import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate +import net.corda.core.internal.toX509CertHolder import net.corda.core.node.services.IdentityService +import net.corda.core.node.services.UnknownAnonymousPartyException import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.utilities.loggerFor import net.corda.core.utilities.trace @@ -16,16 +18,13 @@ import org.bouncycastle.cert.X509CertificateHolder import java.security.InvalidAlgorithmParameterException import java.security.PublicKey import java.security.cert.* -import java.util.* import java.util.concurrent.ConcurrentHashMap import javax.annotation.concurrent.ThreadSafe -import kotlin.collections.LinkedHashSet /** * Simple identity service which caches parties and provides functionality for efficient lookup. * * @param identities initial set of identities for the service, typically only used for unit tests. - * @param certPaths initial set of certificate paths for the service, typically only used for unit tests. */ @ThreadSafe class InMemoryIdentityService(identities: Iterable = emptySet(), @@ -43,7 +42,7 @@ class InMemoryIdentityService(identities: Iterable = emptyS * Certificate store for certificate authority and intermediary certificates. */ override val caCertStore: CertStore - override val trustRootHolder = X509CertificateHolder(trustRoot.encoded) + override val trustRootHolder = trustRoot.toX509CertHolder() override val trustAnchor: TrustAnchor = TrustAnchor(trustRoot, null) private val keyToParties = ConcurrentHashMap() private val principalToParties = ConcurrentHashMap() @@ -54,7 +53,6 @@ class InMemoryIdentityService(identities: Iterable = emptyS keyToParties.putAll(identities.associateBy { it.owningKey } ) principalToParties.putAll(identities.associateBy { it.name }) confidentialIdentities.forEach { identity -> - require(identity.certPath.certificates.size >= 2) { "Certificate path must at least include subject and issuing certificates" } principalToParties.computeIfAbsent(identity.name) { identity } } } @@ -66,13 +64,10 @@ class InMemoryIdentityService(identities: Iterable = emptyS // TODO: Check the certificate validation logic @Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class) override fun verifyAndRegisterIdentity(identity: PartyAndCertificate): PartyAndCertificate? { - require(identity.certPath.certificates.size >= 2) { "Certificate path must at least include subject and issuing certificates" } // Validate the chain first, before we do anything clever with it identity.verify(trustAnchor) log.trace { "Registering identity $identity" } - require(Arrays.equals(identity.certificate.subjectPublicKeyInfo.encoded, identity.owningKey.encoded)) { "Party certificate must end with party's public key" } - keyToParties[identity.owningKey] = identity // Always keep the first party we registered, as that's the well known identity principalToParties.computeIfAbsent(identity.name) { identity } @@ -83,7 +78,7 @@ class InMemoryIdentityService(identities: Iterable = emptyS override fun certificateFromParty(party: Party): PartyAndCertificate = principalToParties[party.name] ?: throw IllegalArgumentException("Unknown identity ${party.name}") // We give the caller a copy of the data set to avoid any locking problems - override fun getAllIdentities(): Iterable = java.util.ArrayList(keyToParties.values) + override fun getAllIdentities(): Iterable = ArrayList(keyToParties.values) override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]?.party override fun partyFromX500Name(principal: X500Name): Party? = principalToParties[principal]?.party @@ -128,13 +123,13 @@ class InMemoryIdentityService(identities: Iterable = emptyS return results } - @Throws(IdentityService.UnknownAnonymousPartyException::class) + @Throws(UnknownAnonymousPartyException::class) override fun assertOwnership(party: Party, anonymousParty: AnonymousParty) { - val path = keyToParties[anonymousParty.owningKey]?.certPath ?: throw IdentityService.UnknownAnonymousPartyException("Unknown anonymous party ${anonymousParty.owningKey.toStringShort()}") - require(path.certificates.size > 1) { "Certificate path must contain at least two certificates" } - val actual = path.certificates[1] - require(actual is X509Certificate && actual.publicKey == party.owningKey) { "Next certificate in the path must match the party key ${party.owningKey.toStringShort()}." } - val target = path.certificates.first() - require(target is X509Certificate && target.publicKey == anonymousParty.owningKey) { "Certificate path starts with a certificate for the anonymous party" } + val anonymousIdentity = keyToParties[anonymousParty.owningKey] ?: + throw UnknownAnonymousPartyException("Unknown $anonymousParty") + val issuingCert = anonymousIdentity.certPath.certificates[1] + require(issuingCert.publicKey == party.owningKey) { + "Issuing certificate's public key must match the party key ${party.owningKey.toStringShort()}." + } } } diff --git a/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt b/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt index 07bf6b363b..36a2c4f34d 100644 --- a/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt +++ b/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt @@ -3,7 +3,6 @@ package net.corda.node.services.keys import net.corda.core.crypto.ContentSignerBuilder import net.corda.core.crypto.Crypto import net.corda.core.crypto.cert -import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.IdentityService import net.corda.core.utilities.days @@ -35,10 +34,11 @@ fun freshCertificate(identityService: IdentityService, revocationEnabled: Boolean = false): PartyAndCertificate { val issuerCertificate = issuer.certificate val window = X509Utilities.getCertificateValidityWindow(Duration.ZERO, 3650.days, issuerCertificate) - val ourCertificate = X509Utilities.createCertificate(CertificateType.IDENTITY, issuerCertificate.subject, issuerSigner, issuer.name, subjectPublicKey, window) + val ourCertificate = X509Utilities.createCertificate(CertificateType.IDENTITY, issuerCertificate.subject, + issuerSigner, issuer.name, subjectPublicKey, window) val certFactory = CertificateFactory.getInstance("X509") val ourCertPath = certFactory.generateCertPath(listOf(ourCertificate.cert) + issuer.certPath.certificates) - val anonymisedIdentity = PartyAndCertificate(Party(issuer.name, subjectPublicKey), ourCertificate, ourCertPath) + val anonymisedIdentity = PartyAndCertificate(ourCertPath) identityService.verifyAndRegisterIdentity(anonymisedIdentity) return anonymisedIdentity } diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt index 919a744191..829c36bfbf 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt @@ -11,6 +11,7 @@ import net.corda.core.internal.ThreadBox import net.corda.core.internal.concurrent.openFuture import net.corda.core.internal.div import net.corda.core.internal.noneOrSingle +import net.corda.core.internal.toX509CertHolder import net.corda.core.node.NodeInfo import net.corda.core.node.services.NetworkMapCache import net.corda.core.node.services.NetworkMapCache.MapChange @@ -25,7 +26,6 @@ import net.corda.node.services.messaging.NodeLoginModule.Companion.VERIFIER_ROLE import net.corda.node.utilities.X509Utilities import net.corda.node.utilities.X509Utilities.CORDA_CLIENT_TLS import net.corda.node.utilities.X509Utilities.CORDA_ROOT_CA -import net.corda.node.utilities.getX509Certificate import net.corda.node.utilities.loadKeyStore import net.corda.nodeapi.* import net.corda.nodeapi.ArtemisMessagingComponent.Companion.NODE_USER @@ -52,7 +52,6 @@ import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal import org.apache.activemq.artemis.utils.ConfigurationHelper import org.bouncycastle.asn1.x500.X500Name -import org.bouncycastle.cert.X509CertificateHolder import rx.Subscription import java.io.IOException import java.math.BigInteger @@ -273,12 +272,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration, private fun createArtemisSecurityManager(): ActiveMQJAASSecurityManager { val keyStore = loadKeyStore(config.sslKeystore, config.keyStorePassword) val trustStore = loadKeyStore(config.trustStoreFile, config.trustStorePassword) - val ourCertificate = keyStore.getX509Certificate(CORDA_CLIENT_TLS) - // This is a sanity check and should not fail unless things have been misconfigured - require(ourCertificate.subject == config.myLegalName) { - "Legal name does not match with our subject CN: ${ourCertificate.subject}" - } val defaultCertPolicies = mapOf( PEER_ROLE to CertificateChainCheckPolicy.RootMustMatch, NODE_ROLE to CertificateChainCheckPolicy.LeafMustMatch, @@ -512,12 +506,12 @@ private class VerifyingNettyConnector(configuration: MutableMap, "misconfiguration by the remote peer or an SSL man-in-the-middle attack!" } // Make sure certificate has the same name. - val peerCertificate = X509CertificateHolder(session.peerCertificateChain.first().encoded) + val peerCertificate = session.peerCertificateChain[0].toX509CertHolder() require(peerCertificate.subject == expectedLegalName) { "Peer has wrong subject name in the certificate - expected $expectedLegalName but got ${peerCertificate.subject}. This is either a fatal " + "misconfiguration by the remote peer or an SSL man-in-the-middle attack!" } - X509Utilities.validateCertificateChain(X509CertificateHolder(session.localCertificates.last().encoded), *session.peerCertificates) + X509Utilities.validateCertificateChain(session.localCertificates.last().toX509CertHolder(), *session.peerCertificates) server.onTcpConnection(peerLegalName) } catch (e: IllegalArgumentException) { connection.close() diff --git a/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapService.kt b/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapService.kt index 1cb7de5292..f8f340f817 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapService.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapService.kt @@ -21,6 +21,7 @@ import java.util.Collections.synchronizedMap class PersistentNetworkMapService(services: ServiceHubInternal, minimumPlatformVersion: Int) : AbstractNetworkMapService(services, minimumPlatformVersion) { + // Only the node_party_path column is needed to reconstruct a PartyAndCertificate but we have the others for human readability private object Table : JDBCHashedTable("${NODE_DATABASE_PREFIX}network_map_nodes") { val nodeParty = partyAndCertificate("node_party_name", "node_party_key", "node_party_certificate", "node_party_path") val registrationInfo = blob("node_registration_info") @@ -28,16 +29,15 @@ class PersistentNetworkMapService(services: ServiceHubInternal, minimumPlatformV override val nodeRegistrations: MutableMap = synchronizedMap(object : AbstractJDBCHashMap(Table, loadOnInit = true) { // TODO: We should understand an X500Name database field type, rather than manually doing the conversion ourselves - override fun keyFromRow(row: ResultRow): PartyAndCertificate = PartyAndCertificate(X500Name(row[table.nodeParty.name]), row[table.nodeParty.owningKey], - row[table.nodeParty.certificate], row[table.nodeParty.certPath]) + override fun keyFromRow(row: ResultRow): PartyAndCertificate = PartyAndCertificate(row[table.nodeParty.certPath]) override fun valueFromRow(row: ResultRow): NodeRegistrationInfo = deserializeFromBlob(row[table.registrationInfo]) override fun addKeyToInsert(insert: InsertStatement, entry: Map.Entry, finalizables: MutableList<() -> Unit>) { insert[table.nodeParty.name] = entry.key.name.toString() insert[table.nodeParty.owningKey] = entry.key.owningKey - insert[table.nodeParty.certPath] = entry.key.certPath insert[table.nodeParty.certificate] = entry.key.certificate + insert[table.nodeParty.certPath] = entry.key.certPath } override fun addValueToInsert(insert: InsertStatement, entry: Map.Entry, finalizables: MutableList<() -> Unit>) { diff --git a/node/src/main/kotlin/net/corda/node/utilities/KeyStoreUtilities.kt b/node/src/main/kotlin/net/corda/node/utilities/KeyStoreUtilities.kt index b429f2e09e..fbe2947a70 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/KeyStoreUtilities.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/KeyStoreUtilities.kt @@ -1,8 +1,11 @@ package net.corda.node.utilities -import net.corda.core.crypto.* +import net.corda.core.crypto.CertificateAndKeyPair +import net.corda.core.crypto.Crypto +import net.corda.core.crypto.cert import net.corda.core.internal.exists import net.corda.core.internal.read +import net.corda.core.internal.toX509CertHolder import net.corda.core.internal.write import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509CertificateHolder @@ -145,8 +148,8 @@ fun KeyStore.getCertificateAndKeyPair(alias: String, keyPassword: String): Certi * @return The X509Certificate found in the KeyStore under the specified alias. */ fun KeyStore.getX509Certificate(alias: String): X509CertificateHolder { - val encoded = getCertificate(alias)?.encoded ?: throw IllegalArgumentException("No certificate under alias \"$alias\"") - return X509CertificateHolder(encoded) + val certificate = getCertificate(alias) ?: throw IllegalArgumentException("No certificate under alias \"$alias\"") + return certificate.toX509CertHolder() } /** @@ -206,5 +209,5 @@ class KeyStoreWrapper(private val storePath: Path, private val storePassword: St fun getCertificate(alias: String): Certificate = keyStore.getCertificate(alias) - fun certificateAndKeyPair(alias: String) = keyStore.getCertificateAndKeyPair(alias, storePassword) + fun certificateAndKeyPair(alias: String): CertificateAndKeyPair = keyStore.getCertificateAndKeyPair(alias, storePassword) } diff --git a/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt index 4507bd395a..c7809739fb 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt @@ -7,7 +7,7 @@ import net.corda.core.crypto.generateKeyPair import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate -import net.corda.core.node.services.IdentityService +import net.corda.core.node.services.UnknownAnonymousPartyException import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.utilities.CertificateType import net.corda.node.utilities.X509Utilities @@ -90,10 +90,10 @@ class InMemoryIdentityServiceTests { val txKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate) // TODO: Generate certificate with an EdDSA key rather than ECDSA - val identity = Party(CertificateAndKeyPair(rootCert, rootKey)) + val identity = Party(rootCert) val txIdentity = AnonymousParty(txKey.public) - assertFailsWith { + assertFailsWith { service.assertOwnership(identity, txIdentity) } } @@ -107,7 +107,7 @@ class InMemoryIdentityServiceTests { fun `get anonymous identity by key`() { val trustRoot = DUMMY_CA val (alice, aliceTxIdentity) = createParty(ALICE.name, trustRoot) - val (bob, bobTxIdentity) = createParty(ALICE.name, trustRoot) + val (_, bobTxIdentity) = createParty(ALICE.name, trustRoot) // Now we have identities, construct the service and let it know about both val service = InMemoryIdentityService(setOf(alice), emptySet(), trustRoot.certificate.cert) @@ -163,7 +163,7 @@ class InMemoryIdentityServiceTests { val txKey = Crypto.generateKeyPair() val txCert = X509Utilities.createCertificate(CertificateType.IDENTITY, issuer.certificate, issuerKeyPair, x500Name, txKey.public) val txCertPath = certFactory.generateCertPath(listOf(txCert.cert) + issuer.certPath.certificates) - return Pair(issuer, PartyAndCertificate(Party(x500Name, txKey.public), txCert, txCertPath)) + return Pair(issuer, PartyAndCertificate(txCertPath)) } /** diff --git a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt index 51de115d1f..da5569e280 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt @@ -9,12 +9,12 @@ import net.corda.core.crypto.cert import net.corda.core.crypto.commonName import net.corda.core.internal.exists import net.corda.core.internal.toTypedArray +import net.corda.core.internal.toX509CertHolder import net.corda.node.utilities.X509Utilities import net.corda.node.utilities.loadKeyStore import net.corda.testing.ALICE import net.corda.testing.getTestX509Name import net.corda.testing.testNodeConfiguration -import org.bouncycastle.cert.X509CertificateHolder import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder @@ -68,7 +68,7 @@ class NetworkRegistrationHelperTest { assertFalse(containsAlias(X509Utilities.CORDA_CLIENT_TLS)) val certificateChain = getCertificateChain(X509Utilities.CORDA_CLIENT_CA) assertEquals(3, certificateChain.size) - assertEquals(listOf("CORDA_CLIENT_CA", "CORDA_INTERMEDIATE_CA", "CORDA_ROOT_CA"), certificateChain.map { X509CertificateHolder(it.encoded).subject.commonName }) + assertEquals(listOf("CORDA_CLIENT_CA", "CORDA_INTERMEDIATE_CA", "CORDA_ROOT_CA"), certificateChain.map { it.toX509CertHolder().subject.commonName }) } sslKeystore.run { @@ -78,7 +78,7 @@ class NetworkRegistrationHelperTest { assertTrue(containsAlias(X509Utilities.CORDA_CLIENT_TLS)) val certificateChain = getCertificateChain(X509Utilities.CORDA_CLIENT_TLS) assertEquals(4, certificateChain.size) - assertEquals(listOf("CORDA_CLIENT_CA", "CORDA_CLIENT_CA", "CORDA_INTERMEDIATE_CA", "CORDA_ROOT_CA"), certificateChain.map { X509CertificateHolder(it.encoded).subject.commonName }) + assertEquals(listOf("CORDA_CLIENT_CA", "CORDA_CLIENT_CA", "CORDA_INTERMEDIATE_CA", "CORDA_ROOT_CA"), certificateChain.map { it.toX509CertHolder().subject.commonName }) } trustStore.run { diff --git a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/CommercialPaperIssueFlow.kt b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/CommercialPaperIssueFlow.kt index 2df13766d3..ba813d6df3 100644 --- a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/CommercialPaperIssueFlow.kt +++ b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/CommercialPaperIssueFlow.kt @@ -3,11 +3,9 @@ package net.corda.traderdemo.flow import co.paralleluniverse.fibers.Suspendable import net.corda.contracts.CommercialPaper import net.corda.core.contracts.Amount -import net.corda.finance.`issued by` import net.corda.core.crypto.SecureHash import net.corda.core.flows.FinalityFlow import net.corda.core.flows.FlowLogic -import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC import net.corda.core.identity.Party import net.corda.core.transactions.SignedTransaction @@ -16,13 +14,13 @@ import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.days import net.corda.core.utilities.seconds +import net.corda.finance.`issued by` import java.time.Instant import java.util.* /** * Flow for the Bank of Corda node to issue some commercial paper to the seller's node, to sell to the buyer. */ -@InitiatingFlow @StartableByRPC class CommercialPaperIssueFlow(val amount: Amount, val issueRef: OpaqueBytes, diff --git a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt index ed759632be..663fe30dcf 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt @@ -207,7 +207,7 @@ fun getTestPartyAndCertificate(party: Party, trustRoot: CertificateAndKeyPair = val certFactory = CertificateFactory.getInstance("X509") 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(party, certHolder, certPath) + return PartyAndCertificate(certPath) } /** diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt index af092dd5f0..603de51d4c 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt @@ -149,7 +149,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, // We only need to override the messaging service here, as currently everything that hits disk does so // through the java.nio API which we are already mocking via Jimfs. - override fun makeMessagingService(): MessagingService { + override fun makeMessagingService(legalIdentity: PartyAndCertificate): MessagingService { require(id >= 0) { "Node ID must be zero or positive, was passed: " + id } return mockNet.messagingNetwork.createNodeWithID( !mockNet.threadPerNode,