From b3ca36132f98f84a0132a8e9ad093547674c1655 Mon Sep 17 00:00:00 2001 From: Patrick Kuo Date: Thu, 7 Dec 2017 13:22:41 +0000 Subject: [PATCH] Use network map objects from corda instead of stubs (#146) * * change corda dependencies to 3.0-NETWORKMAP_SNAPSHOT * packages move fix * fix up after rebase * rename test * address PR issues * address PR issues * fix failing test --- .idea/compiler.xml | 4 +- network-management/build.gradle | 2 - .../doorman/DoormanIntegrationTest.kt | 4 +- .../common/persistence/NetworkMapStorage.kt | 27 ++-- .../PersistentNetworkMapStorage.kt | 125 +++++------------- .../common/persistence/SchemaService.kt | 0 .../persistence/entity/NetworkMapEntity.kt | 27 ++-- .../persistence/entity/NodeInfoEntity.kt | 8 +- .../common/signer/NetworkMapSigner.kt | 35 +---- .../networkmanage/common/signer/Signer.kt | 12 +- .../corda/networkmanage/common/utils/Utils.kt | 4 + .../r3/corda/networkmanage/doorman/Main.kt | 8 +- .../doorman/signer/CsrHandler.kt | 2 +- .../doorman/signer/LocalSigner.kt | 11 +- .../doorman/webservice/NodeInfoWebService.kt | 2 +- .../hsm/authentication/Authenticator.kt | 9 +- .../hsm/signer/HsmNetworkMapSigner.kt | 16 +-- .../DBCertificateRequestStorageTest.kt | 1 - .../persistence/DBNetworkMapStorageTest.kt | 57 ++++---- .../common/signer/NetworkMapSignerTest.kt | 60 +++++---- .../doorman/NodeInfoWebServiceTest.kt | 17 ++- .../hsm/authentication/AuthenticatorTest.kt | 23 ++-- 22 files changed, 191 insertions(+), 263 deletions(-) create mode 100644 network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/SchemaService.kt diff --git a/.idea/compiler.xml b/.idea/compiler.xml index d72e565e78..198a957a38 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -15,6 +15,8 @@ + + @@ -172,4 +174,4 @@ - + \ No newline at end of file diff --git a/network-management/build.gradle b/network-management/build.gradle index b6bd4e5ac6..38512eca90 100644 --- a/network-management/build.gradle +++ b/network-management/build.gradle @@ -56,9 +56,7 @@ dependencies { compile fileTree(dir: 'libs', include: '*.jar') compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - compile "net.corda:corda-core:$corda_dependency_version" compile "net.corda:corda-node-api:$corda_dependency_version" - testCompile "net.corda:corda-test-utils:$corda_dependency_version" testCompile "net.corda:corda-node-driver:$corda_dependency_version" testCompile "net.corda:corda-test-common:$corda_dependency_version" diff --git a/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/doorman/DoormanIntegrationTest.kt b/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/doorman/DoormanIntegrationTest.kt index dbd2f66527..093b04fc38 100644 --- a/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/doorman/DoormanIntegrationTest.kt +++ b/network-management/src/integration-test/kotlin/com/r3/corda/networkmanage/doorman/DoormanIntegrationTest.kt @@ -92,9 +92,7 @@ class DoormanIntegrationTest { doorman.close() } - //TODO remove @Ignore once PR https://github.com/corda/corda/pull/2054 is merged @Test - @Ignore fun `nodeInfo is published to the network map`() { // Given val rootCertAndKey = createDoormanRootCertificateAndKeyPair() @@ -111,6 +109,8 @@ class DoormanIntegrationTest { whenever(it.compatibilityZoneURL).thenReturn(URL("http://${doormanHostAndPort.host}:${doormanHostAndPort.port}")) whenever(it.emailAddress).thenReturn("iTest@R3.com") } + config.rootCaCertFile.parent.createDirectories() + X509Utilities.saveCertificateAsPEMFile(rootCertAndKey.certificate, config.rootCaCertFile) NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore() diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/NetworkMapStorage.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/NetworkMapStorage.kt index 629a5d8d7e..4a91aa0c7c 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/NetworkMapStorage.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/NetworkMapStorage.kt @@ -1,8 +1,8 @@ package com.r3.corda.networkmanage.common.persistence -import com.r3.corda.networkmanage.common.signer.SignedNetworkMap import net.corda.core.crypto.SecureHash import net.corda.nodeapi.internal.NetworkParameters +import net.corda.nodeapi.internal.SignedNetworkMap /** * Data access object interface for NetworkMap persistence layer @@ -15,16 +15,13 @@ interface NetworkMapStorage { fun getCurrentNetworkMap(): SignedNetworkMap? /** - * Retrieves current map node info hashes only. Hashes are further filtered by the [certificateStatuses] parameter - * that restricts considered node info to only those which [CertificateStatus] value corresponds to one in the passed - * collection. If null or empty list is passed then filtering has no effect and all node info hashes from the current - * network map are returned. - * @param certificateStatuses certificate statuses to be used in the node info filtering. Node info hash is returned - * in the result collection only if it is in the current network map and its certificate status belongs to the - * [certificateStatuses] collection or if [certificateStatuses] collection is null or empty. - * @return list of current network map node info hashes satisfying the filtering criteria given by [certificateStatuses]. + * Retrieves node info hashes where the certificate status matches [certificateStatus]. + * + * @param certificateStatus certificate status to be used in the node info filtering. Node info hash is returned + * in the result collection if its certificate status matches [certificateStatus]. + * @return list of node info hashes satisfying the filtering criteria given by [certificateStatus]. */ - fun getCurrentNetworkMapNodeInfoHashes(certificateStatuses: List): List + fun getNodeInfoHashes(certificateStatus: CertificateStatus): List /** * Persists a new instance of the signed network map. @@ -32,17 +29,11 @@ interface NetworkMapStorage { */ fun saveNetworkMap(signedNetworkMap: SignedNetworkMap) - /** - * Retrieve all node info hashes for all node info with valid certificates, - * that are not associated with any network map yet. - */ - fun getDetachedAndValidNodeInfoHashes(): List - /** * Retrieve network parameters by their hash. * @return network parameters corresponding to the given hash or null if it does not exist */ - fun getNetworkParameters(parameterHash: SecureHash): NetworkParameters + fun getNetworkParameters(parameterHash: SecureHash): NetworkParameters? /** * Retrieve network map parameters. @@ -54,7 +45,7 @@ interface NetworkMapStorage { * Persists given network parameters. * @return hash corresponding to newly create network parameters entry */ - fun putNetworkParameters(networkParameters: NetworkParameters): SecureHash + fun saveNetworkParameters(networkParameters: NetworkParameters): SecureHash /** * Retrieves the latest (i.e. most recently inserted) network parameters diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistentNetworkMapStorage.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistentNetworkMapStorage.kt index f8f00bb257..477e2b7003 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistentNetworkMapStorage.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistentNetworkMapStorage.kt @@ -1,77 +1,64 @@ package com.r3.corda.networkmanage.common.persistence -import com.r3.corda.networkmanage.common.persistence.entity.NetworkMapEntity -import com.r3.corda.networkmanage.common.persistence.entity.NetworkParametersEntity -import com.r3.corda.networkmanage.common.persistence.entity.NodeInfoEntity -import com.r3.corda.networkmanage.common.signer.NetworkMap -import com.r3.corda.networkmanage.common.signer.SignedNetworkMap +import com.r3.corda.networkmanage.common.persistence.entity.* import net.corda.core.crypto.SecureHash import net.corda.core.crypto.sha256 +import net.corda.core.serialization.SerializedBytes +import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize +import net.corda.nodeapi.internal.NetworkMap import net.corda.nodeapi.internal.NetworkParameters +import net.corda.nodeapi.internal.SignedNetworkMap import net.corda.nodeapi.internal.persistence.CordaPersistence -import org.hibernate.Session -import org.hibernate.jpa.QueryHints /** * Database implementation of the [NetworkMapStorage] interface */ class PersistentNetworkMapStorage(private val database: CordaPersistence) : NetworkMapStorage { override fun getCurrentNetworkMap(): SignedNetworkMap? = database.transaction { - val networkMapEntity = getCurrentNetworkMapEntity(getNetworkMapWithNodeInfoAndParametersHint(session)) + val networkMapEntity = getCurrentNetworkMapEntity() networkMapEntity?.let { - val nodeInfoHashes = it.nodeInfoList.map { it.nodeInfoHash } - val networkParameterHash = it.parameters.parametersHash val signatureAndCertPath = it.signatureAndCertificate() - SignedNetworkMap(NetworkMap(nodeInfoHashes, networkParameterHash), signatureAndCertPath!!) + SignedNetworkMap(SerializedBytes(it.networkMap), signatureAndCertPath) } } override fun getCurrentNetworkParameters(): NetworkParameters? = database.transaction { - getCurrentNetworkMapEntity(getNetworkMapWithParametersHint(session))?.parameters?.networkParameters() + getCurrentNetworkMapEntity()?.let { + val parameterHash = it.networkMap.deserialize().networkParameterHash + getNetworkParameters(parameterHash) + } } override fun saveNetworkMap(signedNetworkMap: SignedNetworkMap) { database.transaction { - val networkMap = signedNetworkMap.networkMap - val signatureAndCertPath = signedNetworkMap.signatureData - val signature = signatureAndCertPath.signature - val networkParametersEntity = getNetworkParametersEntity(networkMap.parametersHash) - networkParametersEntity ?: throw IllegalArgumentException("Error when retrieving network parameters entity for network map signing! - Entity does not exist") val networkMapEntity = NetworkMapEntity( - parameters = networkParametersEntity, - signatureBytes = signature.bytes, - certificatePathBytes = signatureAndCertPath.certPath.serialize().bytes + networkMap = signedNetworkMap.raw.bytes, + signature = signedNetworkMap.sig.signatureBytes, + certificate = signedNetworkMap.sig.by.encoded ) session.save(networkMapEntity) - networkMap.nodeInfoHashes.forEach { - val nodeInfoEntity = session.find(NodeInfoEntity::class.java, it) - session.merge(nodeInfoEntity.copy(networkMap = networkMapEntity)) + } + } + + override fun getNetworkParameters(parameterHash: SecureHash): NetworkParameters? { + return getNetworkParametersEntity(parameterHash.toString())?.networkParameters() + } + + override fun getNodeInfoHashes(certificateStatus: CertificateStatus): List = database.transaction { + val builder = session.criteriaBuilder + val query = builder.createQuery(String::class.java).run { + from(NodeInfoEntity::class.java).run { + select(get(NodeInfoEntity::nodeInfoHash.name)) + .where(builder.equal(get(NodeInfoEntity::certificateSigningRequest.name) + .get(CertificateSigningRequestEntity::certificateData.name) + .get(CertificateDataEntity::certificateStatus.name), certificateStatus)) } } + session.createQuery(query).resultList.map { SecureHash.parse(it) } } - override fun getNetworkParameters(parameterHash: SecureHash): NetworkParameters { - val entity = getNetworkParametersEntity(parameterHash.toString()) - if (entity != null) { - return entity.networkParameters() - } else { - throw NoSuchElementException("Network parameters with $parameterHash do not exist") - } - } - - override fun getCurrentNetworkMapNodeInfoHashes(certificateStatuses: List): List = database.transaction { - val networkMapEntity = getCurrentNetworkMapEntity(getNetworkMapWithNodeInfoAndCsrHint(session)) - if (networkMapEntity != null) { - networkMapEntity.nodeInfoList.filter({ - certificateStatuses.isEmpty() || certificateStatuses.contains(it.certificateSigningRequest?.certificateData?.certificateStatus) - }).map { SecureHash.parse(it.nodeInfoHash) } - } else { - emptyList() - } - } - - override fun putNetworkParameters(networkParameters: NetworkParameters): SecureHash = database.transaction { + override fun saveNetworkParameters(networkParameters: NetworkParameters): SecureHash = database.transaction { val bytes = networkParameters.serialize().bytes val hash = bytes.sha256() session.save(NetworkParametersEntity( @@ -94,29 +81,16 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw session.createQuery(query).resultList.first() } - override fun getDetachedAndValidNodeInfoHashes(): List = database.transaction { - val builder = session.criteriaBuilder - // Get signed NodeInfoEntities - val query = builder.createQuery(NodeInfoEntity::class.java).run { - from(NodeInfoEntity::class.java).run { - where(builder.and( - builder.isNull(get(NodeInfoEntity::networkMap.name)), - builder.isNotNull(get(NodeInfoEntity::signatureBytes.name)))) - } - } - session.createQuery(query).resultList.map { SecureHash.parse(it.nodeInfoHash) } - } - - private fun getCurrentNetworkMapEntity(hint: Pair): NetworkMapEntity? = database.transaction { + private fun getCurrentNetworkMapEntity(): NetworkMapEntity? = database.transaction { val builder = session.criteriaBuilder val query = builder.createQuery(NetworkMapEntity::class.java).run { from(NetworkMapEntity::class.java).run { - where(builder.isNotNull(get(NetworkMapEntity::signatureBytes.name))) + where(builder.isNotNull(get(NetworkMapEntity::signature.name))) orderBy(builder.desc(get(NetworkMapEntity::version.name))) } } // We just want the last signed entry - session.createQuery(query).setHint(hint.first, hint.second).resultList.firstOrNull() + session.createQuery(query).resultList.firstOrNull() } private fun getNetworkParametersEntity(parameterHash: String): NetworkParametersEntity? = database.transaction { @@ -124,33 +98,4 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw builder.equal(path.get(NetworkParametersEntity::parametersHash.name), parameterHash) } } - - /** - * Creates Hibernate query hint for pulling [NetworkParametersEntity] when querying for [NetworkMapEntity] - */ - private fun getNetworkMapWithParametersHint(session: Session): Pair { - val graph = session.createEntityGraph(NetworkMapEntity::class.java) - graph.addAttributeNodes(NetworkMapEntity::parameters.name) - return QueryHints.HINT_LOADGRAPH to graph - } - - /** - * Creates Hibernate query hint for pulling [NodeInfoEntity] and [CertificateSigningRequestEntity] when querying for [NetworkMapEntity] - */ - private fun getNetworkMapWithNodeInfoAndCsrHint(session: Session): Pair { - val graph = session.createEntityGraph(NetworkMapEntity::class.java) - val subGraph = graph.addSubgraph(NetworkMapEntity::nodeInfoList.name, NodeInfoEntity::class.java) - subGraph.addAttributeNodes(NodeInfoEntity::certificateSigningRequest.name) - return QueryHints.HINT_LOADGRAPH to graph - } - - /** - * Creates Hibernate query hint for pulling [NodeInfoEntity] and [NetworkParametersEntity] when querying for [NetworkMapEntity] - */ - private fun getNetworkMapWithNodeInfoAndParametersHint(session: Session): Pair { - val graph = session.createEntityGraph(NetworkMapEntity::class.java) - graph.addAttributeNodes(NetworkMapEntity::nodeInfoList.name) - graph.addAttributeNodes(NetworkMapEntity::parameters.name) - return QueryHints.HINT_LOADGRAPH to graph - } -} \ No newline at end of file +} diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/SchemaService.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/SchemaService.kt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/entity/NetworkMapEntity.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/entity/NetworkMapEntity.kt index 19ab90f2b7..ff9865a6e1 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/entity/NetworkMapEntity.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/entity/NetworkMapEntity.kt @@ -1,8 +1,7 @@ package com.r3.corda.networkmanage.common.persistence.entity -import com.r3.corda.networkmanage.common.signer.SignatureAndCertPath -import net.corda.core.crypto.DigitalSignature -import net.corda.core.serialization.deserialize +import net.corda.nodeapi.internal.DigitalSignatureWithCert +import net.corda.nodeapi.internal.crypto.X509CertificateFactory import javax.persistence.* @Entity @@ -12,27 +11,23 @@ class NetworkMapEntity( @GeneratedValue(strategy = GenerationType.SEQUENCE) val version: Long? = null, - // Reverting relation ownership due to (potentially) unlimited number of node info items. - @OneToMany(mappedBy = "networkMap", fetch = FetchType.LAZY) - val nodeInfoList: List = mutableListOf(), - - @OneToOne - @JoinColumn(name = "network_parameters") - val parameters: NetworkParametersEntity, + @Lob + @Column(name = "serialized_network_map") + val networkMap: ByteArray, @Lob - @Column(name = "signature_bytes") - val signatureBytes: ByteArray, + @Column(name = "signature") + val signature: ByteArray, @Lob - @Column(name = "certificate_path_bytes") - val certificatePathBytes: ByteArray + @Column(name = "certificate") + val certificate: ByteArray ) { /** * Deserializes NetworkMapEntity.signatureBytes into the [SignatureAndCertPath] instance */ - fun signatureAndCertificate(): SignatureAndCertPath? { - return SignatureAndCertPath(DigitalSignature(signatureBytes), certificatePathBytes.deserialize()) + fun signatureAndCertificate(): DigitalSignatureWithCert { + return DigitalSignatureWithCert(X509CertificateFactory().generateCertificate(certificate.inputStream()), signature) } } \ No newline at end of file diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/entity/NodeInfoEntity.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/entity/NodeInfoEntity.kt index 3161539202..78e450aea9 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/entity/NodeInfoEntity.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/entity/NodeInfoEntity.kt @@ -18,10 +18,6 @@ class NodeInfoEntity( @JoinColumn(name = "certificate_signing_request", nullable = true) val certificateSigningRequest: CertificateSigningRequestEntity? = null, - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "network_map", nullable = true) - val networkMap: NetworkMapEntity? = null, - @Lob @Column(name = "node_info_bytes") val nodeInfoBytes: ByteArray, @@ -55,7 +51,6 @@ class NodeInfoEntity( } fun copy(nodeInfoHash: String = this.nodeInfoHash, - networkMap: NetworkMapEntity? = this.networkMap, certificateSigningRequest: CertificateSigningRequestEntity? = this.certificateSigningRequest, nodeInfoBytes: ByteArray = this.nodeInfoBytes, signatureBytes: ByteArray? = this.signatureBytes, @@ -68,8 +63,7 @@ class NodeInfoEntity( nodeInfoBytes = nodeInfoBytes, signatureBytes = signatureBytes, signaturePublicKeyBytes = signaturePublicKeyBytes, - signaturePublicKeyAlgorithm = signaturePublicKeyAlgorithm, - networkMap = networkMap + signaturePublicKeyAlgorithm = signaturePublicKeyAlgorithm ) } } diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/NetworkMapSigner.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/NetworkMapSigner.kt index 55ffb21286..438ad8c17b 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/NetworkMapSigner.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/NetworkMapSigner.kt @@ -2,43 +2,22 @@ package com.r3.corda.networkmanage.common.signer import com.r3.corda.networkmanage.common.persistence.CertificateStatus import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage -import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.serialize +import net.corda.nodeapi.internal.NetworkMap +import net.corda.nodeapi.internal.SignedNetworkMap -/** - * Encapsulates the network map signing procedure. - * To sign a network map following steps need to be done: - * 1) Collect all node info data that has been signed and has valid certificates - * 2) Retrieve most up-to-date network parameters - * 3) Sign hashed version of the network map - * 4) Persist network map data together with its signature - * Once the network map is signed it is considered to be the current network map. - * - * This class resides in the common package as it is intended to be used in both local and distributed deployments. - * This means that it can be executed by a remote (e.g. HSM) signing service or locally by Doorman. - */ -@CordaSerializable -data class NetworkMap(val nodeInfoHashes: List, val parametersHash: String) - -@CordaSerializable -data class SignedNetworkMap(val networkMap: NetworkMap, val signatureData: SignatureAndCertPath) - -class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, - private val signer: Signer) { +class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private val signer: Signer) { /** * Signs the network map. */ fun signNetworkMap() { val currentSignedNetworkMap = networkMapStorage.getCurrentNetworkMap() - val currentNetworkMapValidNodeInfo = networkMapStorage.getCurrentNetworkMapNodeInfoHashes(listOf(CertificateStatus.VALID)) - val detachedValidNodeInfo = networkMapStorage.getDetachedAndValidNodeInfoHashes() - val nodeInfoHashes = currentNetworkMapValidNodeInfo + detachedValidNodeInfo + val nodeInfoHashes = networkMapStorage.getNodeInfoHashes(CertificateStatus.VALID) val networkParameters = networkMapStorage.getLatestNetworkParameters() - val networkMap = NetworkMap(nodeInfoHashes.map { it.toString() }, networkParameters.serialize().hash.toString()) - if (networkMap != currentSignedNetworkMap?.networkMap) { + val networkMap = NetworkMap(nodeInfoHashes, networkParameters.serialize().hash) + if (networkMap != currentSignedNetworkMap?.verified()) { val digitalSignature = signer.sign(networkMap.serialize().bytes) - require(digitalSignature != null) { "Error while signing network map." } - val signedHashedNetworkMap = SignedNetworkMap(networkMap, digitalSignature!!) + val signedHashedNetworkMap = SignedNetworkMap(networkMap.serialize(), digitalSignature) networkMapStorage.saveNetworkMap(signedHashedNetworkMap) } } diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/Signer.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/Signer.kt index ee47e8825f..ed43651748 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/Signer.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/Signer.kt @@ -2,19 +2,19 @@ package com.r3.corda.networkmanage.common.signer import net.corda.core.crypto.DigitalSignature import net.corda.core.serialization.CordaSerializable +import net.corda.nodeapi.internal.DigitalSignatureWithCert import java.security.cert.CertPath -@CordaSerializable -data class SignatureAndCertPath(val signature: DigitalSignature, val certPath: CertPath) - /** * An interface for arbitrary data signing functionality. */ interface Signer { - /** * Signs given [data]. The signing key selction strategy is left to the implementing class. * @return [SignatureAndCertPath] that encapsulates the signature and the certificate path used in the signing process. + * @throws [AuthenticationException] if fails authentication */ - fun sign(data: ByteArray): SignatureAndCertPath? -} \ No newline at end of file + fun sign(data: ByteArray): DigitalSignatureWithCert +} + +class AuthenticationException : Exception() diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/Utils.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/Utils.kt index 13c3ab188f..a6d46e6ccc 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/Utils.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/Utils.kt @@ -4,7 +4,9 @@ import com.typesafe.config.Config import com.typesafe.config.ConfigFactory import joptsimple.ArgumentAcceptingOptionSpec import joptsimple.OptionParser +import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.sha256 +import net.corda.nodeapi.internal.DigitalSignatureWithCert import net.corda.nodeapi.internal.crypto.X509CertificateFactory import org.bouncycastle.cert.X509CertificateHolder import java.security.PublicKey @@ -41,3 +43,5 @@ fun X509CertificateHolder.toX509Certificate(): X509Certificate = X509Certificate fun buildCertPath(vararg certificates: Certificate): CertPath = X509CertificateFactory().delegate.generateCertPath(certificates.asList()) fun buildCertPath(certPathBytes: ByteArray): CertPath = X509CertificateFactory().delegate.generateCertPath(certPathBytes.inputStream()) + +fun DigitalSignature.WithKey.withCert(cert: X509Certificate): DigitalSignatureWithCert = DigitalSignatureWithCert(cert, bytes) \ No newline at end of file diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt index 510370cd66..913283b54d 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt @@ -11,7 +11,6 @@ import com.r3.corda.networkmanage.doorman.signer.JiraCsrHandler import com.r3.corda.networkmanage.doorman.signer.LocalSigner import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService import com.r3.corda.networkmanage.doorman.webservice.RegistrationWebService -import com.typesafe.config.ConfigFactory import net.corda.core.crypto.Crypto import net.corda.core.identity.CordaX500Name import net.corda.core.internal.createDirectories @@ -32,6 +31,7 @@ import java.io.Closeable import java.net.InetSocketAddress import java.net.URI import java.nio.file.Path +import java.security.cert.X509Certificate import java.time.Instant import java.util.concurrent.Executors import java.util.concurrent.TimeUnit @@ -190,7 +190,7 @@ fun startDoorman(hostAndPort: NetworkHostAndPort, // Persisting new network parameters val currentNetworkParameters = networkMapStorage.getCurrentNetworkParameters() if (currentNetworkParameters == null) { - networkMapStorage.putNetworkParameters(networkMapParameters) + networkMapStorage.saveNetworkParameters(networkMapParameters) } else { throw UnsupportedOperationException("Network parameters already exist. Updating them via the file config is not supported yet.") } @@ -242,8 +242,8 @@ private fun buildLocalSigner(parameters: DoormanParameters): LocalSigner? { val caPrivateKeyPassword = parameters.caPrivateKeyPassword ?: readPassword("CA Private Key Password: ") val keystore = loadOrCreateKeyStore(parameters.keystorePath, keystorePassword) val caKeyPair = keystore.getKeyPair(X509Utilities.CORDA_INTERMEDIATE_CA, caPrivateKeyPassword) - val caCertPath = keystore.getCertificateChain(X509Utilities.CORDA_INTERMEDIATE_CA) - LocalSigner(caKeyPair, caCertPath) + val caCertPath = keystore.getCertificateChain(X509Utilities.CORDA_INTERMEDIATE_CA).map { it as X509Certificate } + LocalSigner(caKeyPair, caCertPath.toTypedArray()) } } diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/signer/CsrHandler.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/signer/CsrHandler.kt index 923143b4a1..0a930434e4 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/signer/CsrHandler.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/signer/CsrHandler.kt @@ -71,7 +71,7 @@ class JiraCsrHandler(private val jiraClient: JiraClient, private val storage: Ce jiraClient.getApprovedRequests().forEach { (id, approvedBy) -> storage.approveRequest(id, approvedBy) } delegate.processApprovedRequests() val signedRequests = storage.getRequests(RequestStatus.SIGNED).mapNotNull { - it.certData?.certPath.let { certs -> it.requestId to certs!! } + it.certData?.certPath?.let { certs -> it.requestId to certs } }.toMap() jiraClient.updateSignedRequests(signedRequests) } diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/signer/LocalSigner.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/signer/LocalSigner.kt index 7139df39fa..900c8c8017 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/signer/LocalSigner.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/signer/LocalSigner.kt @@ -1,12 +1,13 @@ package com.r3.corda.networkmanage.doorman.signer -import com.r3.corda.networkmanage.common.signer.SignatureAndCertPath import com.r3.corda.networkmanage.common.signer.Signer import com.r3.corda.networkmanage.common.utils.buildCertPath import com.r3.corda.networkmanage.common.utils.toX509Certificate +import com.r3.corda.networkmanage.common.utils.withCert import net.corda.core.crypto.sign import net.corda.core.identity.CordaX500Name import net.corda.core.internal.toX509CertHolder +import net.corda.nodeapi.internal.DigitalSignatureWithCert import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.X509Utilities import org.bouncycastle.asn1.x509.GeneralName @@ -16,13 +17,13 @@ import org.bouncycastle.pkcs.PKCS10CertificationRequest import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest import java.security.KeyPair import java.security.cert.CertPath -import java.security.cert.Certificate +import java.security.cert.X509Certificate /** * The [LocalSigner] class signs [PKCS10CertificationRequest] using provided CA key pair and certificate path. * This is intended to be used in testing environment where hardware signing module is not available. */ -class LocalSigner(private val caKeyPair: KeyPair, private val caCertPath: Array) : Signer { +class LocalSigner(private val caKeyPair: KeyPair, private val caCertPath: Array) : Signer { fun createSignedClientCertificate(certificationRequest: PKCS10CertificationRequest): CertPath { // The sub certs issued by the client must satisfy this directory name (or legal name in Corda) constraints, sub certs' directory name must be within client CA's name's subtree, // please see [sun.security.x509.X500Name.isWithinSubtree()] for more information. @@ -41,7 +42,7 @@ class LocalSigner(private val caKeyPair: KeyPair, private val caCertPath: Array< return buildCertPath(clientCertificate, *caCertPath) } - override fun sign(data: ByteArray): SignatureAndCertPath { - return SignatureAndCertPath(caKeyPair.sign(data), buildCertPath(*caCertPath)) + override fun sign(data: ByteArray): DigitalSignatureWithCert { + return caKeyPair.sign(data).withCert(caCertPath.first()) } } diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/webservice/NodeInfoWebService.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/webservice/NodeInfoWebService.kt index 9d325dd628..be35136028 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/webservice/NodeInfoWebService.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/webservice/NodeInfoWebService.kt @@ -74,7 +74,7 @@ class NodeInfoWebService(private val nodeInfoStorage: NodeInfoStorage, } @GET - @Path("{nodeInfoHash}") + @Path("node-info/{nodeInfoHash}") fun getNodeInfo(@PathParam("nodeInfoHash") nodeInfoHash: String): Response { val nodeInfo = nodeInfoStorage.getNodeInfo(SecureHash.parse(nodeInfoHash)) return if (nodeInfo != null) { diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/authentication/Authenticator.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/authentication/Authenticator.kt index 02348e0561..65921ab418 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/authentication/Authenticator.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/authentication/Authenticator.kt @@ -1,6 +1,7 @@ package com.r3.corda.networkmanage.hsm.authentication import CryptoServerJCE.CryptoServerProvider +import com.r3.corda.networkmanage.common.signer.AuthenticationException import com.r3.corda.networkmanage.hsm.configuration.Parameters import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream @@ -25,8 +26,8 @@ class Authenticator(private val provider: CryptoServerProvider, * 1) [CryptoServerProvider] instance * 2) List of strings that corresponds to user names authenticated against the HSM. */ - fun connectAndAuthenticate(block: (CryptoServerProvider, List) -> Unit) { - try { + fun connectAndAuthenticate(block: (CryptoServerProvider, List) -> T): T { + return try { val authenticated = mutableListOf() loop@ while (true) { val user = if (autoUsername.isNullOrEmpty()) { @@ -78,6 +79,8 @@ class Authenticator(private val provider: CryptoServerProvider, } if (!authenticated.isEmpty()) { block(provider, authenticated) + } else { + throw AuthenticationException() } } finally { try { @@ -89,8 +92,8 @@ class Authenticator(private val provider: CryptoServerProvider, } } } - /* + * Configuration class for [CryptoServerProvider] */ data class CryptoServerProviderConfig( diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/signer/HsmNetworkMapSigner.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/signer/HsmNetworkMapSigner.kt index ed63c7fa24..0950b1e3b8 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/signer/HsmNetworkMapSigner.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/signer/HsmNetworkMapSigner.kt @@ -3,15 +3,17 @@ package com.r3.corda.networkmanage.hsm.signer import com.google.common.util.concurrent.MoreExecutors import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage import com.r3.corda.networkmanage.common.signer.NetworkMapSigner -import com.r3.corda.networkmanage.common.signer.SignatureAndCertPath import com.r3.corda.networkmanage.common.signer.Signer -import com.r3.corda.networkmanage.common.utils.buildCertPath +import com.r3.corda.networkmanage.common.utils.withCert import com.r3.corda.networkmanage.hsm.authentication.Authenticator import com.r3.corda.networkmanage.hsm.utils.X509Utilities.getAndInitializeKeyStore import com.r3.corda.networkmanage.hsm.utils.X509Utilities.signData import com.r3.corda.networkmanage.hsm.utils.X509Utilities.verify +import net.corda.core.internal.cert +import net.corda.core.internal.toX509CertHolder import net.corda.core.utilities.loggerFor import net.corda.core.utilities.minutes +import net.corda.nodeapi.internal.DigitalSignatureWithCert import java.security.KeyPair import java.security.PrivateKey import java.time.Duration @@ -59,16 +61,14 @@ class HsmNetworkMapSigner(networkMapStorage: NetworkMapStorage, /** * Signs given data using [CryptoServerJCE.CryptoServerProvider], which connects to the underlying HSM. */ - override fun sign(data: ByteArray): SignatureAndCertPath? { - var result: SignatureAndCertPath? = null - authenticator.connectAndAuthenticate { provider, _ -> + override fun sign(data: ByteArray): DigitalSignatureWithCert { + return authenticator.connectAndAuthenticate { provider, _ -> val keyStore = getAndInitializeKeyStore(provider) val caCertificateChain = keyStore.getCertificateChain(caCertificateKeyName) val caKey = keyStore.getKey(caCertificateKeyName, caPrivateKeyPass.toCharArray()) as PrivateKey val signature = signData(data, KeyPair(caCertificateChain.first().publicKey, caKey), provider) verify(data, signature, caCertificateChain.first().publicKey) - result = SignatureAndCertPath(signature, buildCertPath(*caCertificateChain)) + signature.withCert(caCertificateChain.first().toX509CertHolder().cert) } - return result } -} \ No newline at end of file +} diff --git a/network-management/src/test/kotlin/com/r3/corda/networkmanage/common/persistence/DBCertificateRequestStorageTest.kt b/network-management/src/test/kotlin/com/r3/corda/networkmanage/common/persistence/DBCertificateRequestStorageTest.kt index 36d9893644..e06e2fbdd8 100644 --- a/network-management/src/test/kotlin/com/r3/corda/networkmanage/common/persistence/DBCertificateRequestStorageTest.kt +++ b/network-management/src/test/kotlin/com/r3/corda/networkmanage/common/persistence/DBCertificateRequestStorageTest.kt @@ -11,7 +11,6 @@ import net.corda.core.identity.CordaX500Name import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.persistence.CordaPersistence -import net.corda.nodeapi.internal.persistence.DatabaseConfig import org.assertj.core.api.Assertions.assertThat import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.pkcs.PKCS10CertificationRequest diff --git a/network-management/src/test/kotlin/com/r3/corda/networkmanage/common/persistence/DBNetworkMapStorageTest.kt b/network-management/src/test/kotlin/com/r3/corda/networkmanage/common/persistence/DBNetworkMapStorageTest.kt index 6f208e072b..0cf16e0d71 100644 --- a/network-management/src/test/kotlin/com/r3/corda/networkmanage/common/persistence/DBNetworkMapStorageTest.kt +++ b/network-management/src/test/kotlin/com/r3/corda/networkmanage/common/persistence/DBNetworkMapStorageTest.kt @@ -1,30 +1,30 @@ package com.r3.corda.networkmanage.common.persistence import com.r3.corda.networkmanage.TestBase -import com.r3.corda.networkmanage.common.signer.NetworkMap -import com.r3.corda.networkmanage.common.signer.SignatureAndCertPath -import com.r3.corda.networkmanage.common.signer.SignedNetworkMap import com.r3.corda.networkmanage.common.utils.buildCertPath import com.r3.corda.networkmanage.common.utils.toX509Certificate +import com.r3.corda.networkmanage.common.utils.withCert import net.corda.core.crypto.Crypto import net.corda.core.crypto.SignedData import net.corda.core.crypto.sign import net.corda.core.identity.CordaX500Name import net.corda.core.identity.PartyAndCertificate +import net.corda.core.internal.cert import net.corda.core.node.NodeInfo import net.corda.core.serialization.serialize import net.corda.core.utilities.NetworkHostAndPort +import net.corda.nodeapi.internal.NetworkMap +import net.corda.nodeapi.internal.SignedNetworkMap import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.persistence.CordaPersistence -import net.corda.nodeapi.internal.persistence.DatabaseConfig import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties +import org.assertj.core.api.Assertions.assertThat import org.junit.After import org.junit.Before import org.junit.Test import kotlin.test.assertEquals -import kotlin.test.assertTrue class DBNetworkMapStorageTest : TestBase() { private lateinit var networkMapStorage: NetworkMapStorage @@ -57,7 +57,7 @@ class DBNetworkMapStorageTest : TestBase() { val requestId = requestStorage.saveRequest(createRequest(organisation).first) requestStorage.markRequestTicketCreated(requestId) requestStorage.approveRequest(requestId, "TestUser") - val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) + val keyPair = Crypto.generateKeyPair() val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisation, locality = "London", country = "GB"), keyPair.public) val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate()) requestStorage.putCertificatePath(requestId, certPath, emptyList()) @@ -67,25 +67,28 @@ class DBNetworkMapStorageTest : TestBase() { val nodeInfoHash = nodeInfoStorage.putNodeInfo(SignedData(nodeInfoBytes, keyPair.sign(nodeInfoBytes))) // Create network parameters - val networkParametersHash = networkMapStorage.putNetworkParameters(testNetworkParameters(emptyList())) + val networkParametersHash = networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList())) - val networkMap = NetworkMap(listOf(nodeInfoHash.toString()), networkParametersHash.toString()) - val signatureData = SignatureAndCertPath(keyPair.sign(networkMap.serialize()), certPath) - val signedNetworkMap = SignedNetworkMap(NetworkMap(listOf(nodeInfoHash.toString()), networkParametersHash.toString()), signatureData) + val networkMap = NetworkMap(listOf(nodeInfoHash), networkParametersHash) + val serializedNetworkMap = networkMap.serialize() + val signatureData = intermediateCAKey.sign(serializedNetworkMap).withCert(intermediateCACert.cert) + val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData) // when networkMapStorage.saveNetworkMap(signedNetworkMap) // then val persistedSignedNetworkMap = networkMapStorage.getCurrentNetworkMap() - assertEquals(signedNetworkMap, persistedSignedNetworkMap) + + assertEquals(signedNetworkMap.sig, persistedSignedNetworkMap?.sig) + assertEquals(signedNetworkMap.verified(), persistedSignedNetworkMap?.verified()) } @Test fun `getLatestNetworkParameters returns last inserted`() { // given - networkMapStorage.putNetworkParameters(createNetworkParameters(minimumPlatformVersion = 1)) - networkMapStorage.putNetworkParameters(createNetworkParameters(minimumPlatformVersion = 2)) + networkMapStorage.saveNetworkParameters(createNetworkParameters(minimumPlatformVersion = 1)) + networkMapStorage.saveNetworkParameters(createNetworkParameters(minimumPlatformVersion = 2)) // when val latest = networkMapStorage.getLatestNetworkParameters() @@ -98,20 +101,20 @@ class DBNetworkMapStorageTest : TestBase() { fun `getCurrentNetworkParameters returns current network map parameters`() { // given // Create network parameters - val networkMapParametersHash = networkMapStorage.putNetworkParameters(createNetworkParameters(1)) + val networkMapParametersHash = networkMapStorage.saveNetworkParameters(createNetworkParameters(1)) // Create empty network map val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val intermediateCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = "Corda", locality = "London", country = "GB"), keyPair.public) - val certPath = buildCertPath(intermediateCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate()) // Sign network map making it current network map - val hashedNetworkMap = NetworkMap(emptyList(), networkMapParametersHash.toString()) - val signatureData = SignatureAndCertPath(keyPair.sign(hashedNetworkMap.serialize()), certPath) - val signedNetworkMap = SignedNetworkMap(hashedNetworkMap, signatureData) + val networkMap = NetworkMap(emptyList(), networkMapParametersHash) + val serializedNetworkMap = networkMap.serialize() + val signatureData = keyPair.sign(serializedNetworkMap).withCert(intermediateCert.cert) + val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData) networkMapStorage.saveNetworkMap(signedNetworkMap) // Create new network parameters - networkMapStorage.putNetworkParameters(createNetworkParameters(2)) + networkMapStorage.saveNetworkParameters(createNetworkParameters(2)) // when val result = networkMapStorage.getCurrentNetworkParameters() @@ -121,7 +124,7 @@ class DBNetworkMapStorageTest : TestBase() { } @Test - fun `getDetachedAndValidNodeInfoHashes returns only valid and signed node info hashes`() { + fun `getValidNodeInfoHashes returns only valid and signed node info hashes`() { // given // Create node info. val organisationA = "TestA" @@ -148,19 +151,19 @@ class DBNetworkMapStorageTest : TestBase() { val nodeInfoHashB = nodeInfoStorage.putNodeInfo(SignedData(nodeInfoBBytes, keyPair.sign(nodeInfoBBytes))) // Create network parameters - val networkParametersHash = networkMapStorage.putNetworkParameters(createNetworkParameters()) - val networkMap = NetworkMap(listOf(nodeInfoHashA.toString()), networkParametersHash.toString()) - val signatureData = SignatureAndCertPath(keyPair.sign(networkMap.serialize()), certPathA) - val signedNetworkMap = SignedNetworkMap(networkMap, signatureData) + val networkParametersHash = networkMapStorage.saveNetworkParameters(createNetworkParameters()) + val networkMap = NetworkMap(listOf(nodeInfoHashA), networkParametersHash) + val serializedNetworkMap = networkMap.serialize() + val signatureData = keyPair.sign(serializedNetworkMap).withCert(clientCertA.cert) + val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData) // Sign network map networkMapStorage.saveNetworkMap(signedNetworkMap) // when - val detachedHashes = networkMapStorage.getDetachedAndValidNodeInfoHashes() + val validNodeInfoHash = networkMapStorage.getNodeInfoHashes(CertificateStatus.VALID) // then - assertEquals(1, detachedHashes.size) - assertTrue(detachedHashes.contains(nodeInfoHashB)) + assertThat(validNodeInfoHash).containsOnly(nodeInfoHashA, nodeInfoHashB) } } \ No newline at end of file diff --git a/network-management/src/test/kotlin/com/r3/corda/networkmanage/common/signer/NetworkMapSignerTest.kt b/network-management/src/test/kotlin/com/r3/corda/networkmanage/common/signer/NetworkMapSignerTest.kt index c8dbca7f83..29e05f0ae5 100644 --- a/network-management/src/test/kotlin/com/r3/corda/networkmanage/common/signer/NetworkMapSignerTest.kt +++ b/network-management/src/test/kotlin/com/r3/corda/networkmanage/common/signer/NetworkMapSignerTest.kt @@ -3,9 +3,18 @@ package com.r3.corda.networkmanage.common.signer import com.nhaarman.mockito_kotlin.* import com.r3.corda.networkmanage.TestBase import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage +import com.r3.corda.networkmanage.common.utils.withCert +import net.corda.core.crypto.Crypto import net.corda.core.crypto.SecureHash import net.corda.core.crypto.sha256 +import net.corda.core.crypto.sign +import net.corda.core.identity.CordaX500Name +import net.corda.core.internal.cert import net.corda.core.serialization.serialize +import net.corda.nodeapi.internal.NetworkMap +import net.corda.nodeapi.internal.SignedNetworkMap +import net.corda.nodeapi.internal.crypto.CertificateType +import net.corda.nodeapi.internal.crypto.X509Utilities import org.junit.Before import org.junit.Test import kotlin.test.assertEquals @@ -15,7 +24,10 @@ class NetworkMapSignerTest : TestBase() { private lateinit var signer: Signer private lateinit var networkMapStorage: NetworkMapStorage private lateinit var networkMapSigner: NetworkMapSigner - + private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) + private val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey) + private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) + private val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, CordaX500Name(commonName = "Corda Node Intermediate CA", locality = "London", organisation = "R3 LTD", country = "GB"), intermediateCAKey.public) @Before fun setUp() { signer = mock() @@ -27,30 +39,29 @@ class NetworkMapSignerTest : TestBase() { fun `signNetworkMap builds and signs network map`() { // given val signedNodeInfoHashes = listOf(SecureHash.randomSHA256(), SecureHash.randomSHA256()) - val detachedNodeInfoHashes = listOf(SecureHash.randomSHA256()) val networkMapParameters = createNetworkParameters() + val serializedNetworkMap = NetworkMap(signedNodeInfoHashes, SecureHash.randomSHA256()).serialize() whenever(networkMapStorage.getCurrentNetworkMap()) - .thenReturn(SignedNetworkMap(NetworkMap(signedNodeInfoHashes.map { it.toString() }, "Dummy"), mock())) - whenever(networkMapStorage.getCurrentNetworkMapNodeInfoHashes(any())).thenReturn(signedNodeInfoHashes) - whenever(networkMapStorage.getDetachedAndValidNodeInfoHashes()).thenReturn(detachedNodeInfoHashes) + .thenReturn(SignedNetworkMap(serializedNetworkMap, intermediateCAKey.sign(serializedNetworkMap).withCert(intermediateCACert.cert))) + whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(signedNodeInfoHashes) whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkMapParameters) - whenever(signer.sign(any())).thenReturn(mock()) + whenever(signer.sign(any())).then { + intermediateCAKey.sign(it.arguments.first() as ByteArray).withCert(intermediateCACert.cert) + } // when networkMapSigner.signNetworkMap() // then // Verify networkMapStorage calls - verify(networkMapStorage).getCurrentNetworkMapNodeInfoHashes(any()) - verify(networkMapStorage).getDetachedAndValidNodeInfoHashes() + verify(networkMapStorage).getNodeInfoHashes(any()) verify(networkMapStorage).getLatestNetworkParameters() argumentCaptor().apply { verify(networkMapStorage).saveNetworkMap(capture()) - val networkMap = firstValue.networkMap - assertEquals(networkMapParameters.serialize().hash.toString(), networkMap.parametersHash) - assertEquals(signedNodeInfoHashes.size + detachedNodeInfoHashes.size, networkMap.nodeInfoHashes.size) - assertTrue(networkMap.nodeInfoHashes.containsAll(signedNodeInfoHashes.map { it.toString() })) - assertTrue(networkMap.nodeInfoHashes.containsAll(detachedNodeInfoHashes.map { it.toString() })) + val networkMap = firstValue.verified() + assertEquals(networkMapParameters.serialize().hash, networkMap.networkParameterHash) + assertEquals(signedNodeInfoHashes.size, networkMap.nodeInfoHashes.size) + assertTrue(networkMap.nodeInfoHashes.containsAll(signedNodeInfoHashes)) } } @@ -59,11 +70,11 @@ class NetworkMapSignerTest : TestBase() { // given val networkMapParameters = createNetworkParameters() val networkMapParametersHash = networkMapParameters.serialize().bytes.sha256() - val networkMap = NetworkMap(emptyList(), networkMapParametersHash.toString()) - val signedNetworkMap = SignedNetworkMap(networkMap, mock()) + val networkMap = NetworkMap(emptyList(), networkMapParametersHash) + val serializedNetworkMap = networkMap.serialize() + val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, intermediateCAKey.sign(serializedNetworkMap).withCert(intermediateCACert.cert)) whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(signedNetworkMap) - whenever(networkMapStorage.getCurrentNetworkMapNodeInfoHashes(any())).thenReturn(emptyList()) - whenever(networkMapStorage.getDetachedAndValidNodeInfoHashes()).thenReturn(emptyList()) + whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList()) whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkMapParameters) // when @@ -79,23 +90,22 @@ class NetworkMapSignerTest : TestBase() { // given val networkMapParameters = createNetworkParameters() whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(null) - whenever(networkMapStorage.getCurrentNetworkMapNodeInfoHashes(any())).thenReturn(emptyList()) - whenever(networkMapStorage.getDetachedAndValidNodeInfoHashes()).thenReturn(emptyList()) + whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList()) whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkMapParameters) - whenever(signer.sign(any())).thenReturn(mock()) - + whenever(signer.sign(any())).then { + intermediateCAKey.sign(it.arguments.first() as ByteArray).withCert(intermediateCACert.cert) + } // when networkMapSigner.signNetworkMap() // then // Verify networkMapStorage calls - verify(networkMapStorage).getCurrentNetworkMapNodeInfoHashes(any()) - verify(networkMapStorage).getDetachedAndValidNodeInfoHashes() + verify(networkMapStorage).getNodeInfoHashes(any()) verify(networkMapStorage).getLatestNetworkParameters() argumentCaptor().apply { verify(networkMapStorage).saveNetworkMap(capture()) - val networkMap = firstValue.networkMap - assertEquals(networkMapParameters.serialize().hash.toString(), networkMap.parametersHash) + val networkMap = firstValue.verified() + assertEquals(networkMapParameters.serialize().hash, networkMap.networkParameterHash) } } } \ No newline at end of file diff --git a/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/NodeInfoWebServiceTest.kt b/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/NodeInfoWebServiceTest.kt index 2502acbd5f..3240fd35a1 100644 --- a/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/NodeInfoWebServiceTest.kt +++ b/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/NodeInfoWebServiceTest.kt @@ -6,18 +6,20 @@ import com.nhaarman.mockito_kotlin.times import com.nhaarman.mockito_kotlin.verify import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage -import com.r3.corda.networkmanage.common.signer.NetworkMap -import com.r3.corda.networkmanage.common.signer.SignedNetworkMap import com.r3.corda.networkmanage.common.utils.buildCertPath import com.r3.corda.networkmanage.common.utils.toX509Certificate +import com.r3.corda.networkmanage.common.utils.withCert import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService import net.corda.core.crypto.* import net.corda.core.identity.CordaX500Name import net.corda.core.identity.PartyAndCertificate +import net.corda.core.internal.cert import net.corda.core.node.NodeInfo import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize import net.corda.core.utilities.NetworkHostAndPort +import net.corda.nodeapi.internal.NetworkMap +import net.corda.nodeapi.internal.SignedNetworkMap import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.testing.SerializationEnvironmentRule @@ -97,16 +99,17 @@ class NodeInfoWebServiceTest { @Test fun `get network map`() { - val hashedNetworkMap = NetworkMap(listOf(SecureHash.randomSHA256().toString(), SecureHash.randomSHA256().toString()), SecureHash.randomSHA256().toString()) + val networkMap = NetworkMap(listOf(SecureHash.randomSHA256(), SecureHash.randomSHA256()), SecureHash.randomSHA256()) + val serializedNetworkMap = networkMap.serialize() val networkMapStorage: NetworkMapStorage = mock { - on { getCurrentNetworkMap() }.thenReturn(SignedNetworkMap(hashedNetworkMap, mock())) + on { getCurrentNetworkMap() }.thenReturn(SignedNetworkMap(serializedNetworkMap, intermediateCAKey.sign(serializedNetworkMap).withCert(intermediateCACert.cert))) } DoormanServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(mock(), networkMapStorage)).use { it.start() val conn = URL("http://${it.hostAndPort}/${NodeInfoWebService.NETWORK_MAP_PATH}").openConnection() as HttpURLConnection - val signedHashedNetworkMap = conn.inputStream.readBytes().deserialize() + val signedNetworkMap = conn.inputStream.readBytes().deserialize() verify(networkMapStorage, times(1)).getCurrentNetworkMap() - assertEquals(signedHashedNetworkMap.networkMap, hashedNetworkMap) + assertEquals(signedNetworkMap.verified(), networkMap) } } @@ -126,7 +129,7 @@ class NodeInfoWebServiceTest { DoormanServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(nodeInfoStorage, mock())).use { it.start() - val nodeInfoURL = URL("http://${it.hostAndPort}/${NodeInfoWebService.NETWORK_MAP_PATH}/$nodeInfoHash") + val nodeInfoURL = URL("http://${it.hostAndPort}/${NodeInfoWebService.NETWORK_MAP_PATH}/node-info/$nodeInfoHash") val conn = nodeInfoURL.openConnection() val nodeInfoResponse = conn.inputStream.readBytes().deserialize>() verify(nodeInfoStorage, times(1)).getNodeInfo(nodeInfoHash) diff --git a/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/authentication/AuthenticatorTest.kt b/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/authentication/AuthenticatorTest.kt index 2ae412619a..bb920779f9 100644 --- a/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/authentication/AuthenticatorTest.kt +++ b/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/authentication/AuthenticatorTest.kt @@ -3,9 +3,10 @@ package com.r3.corda.networkmanage.hsm.authentication import CryptoServerJCE.CryptoServerProvider import com.nhaarman.mockito_kotlin.* import com.r3.corda.networkmanage.TestBase +import com.r3.corda.networkmanage.common.signer.AuthenticationException import org.junit.Before import org.junit.Test -import kotlin.test.assertFalse +import kotlin.test.assertFailsWith import kotlin.test.assertTrue class AuthenticatorTest : TestBase() { @@ -24,15 +25,15 @@ class AuthenticatorTest : TestBase() { fun `connectAndAuthenticate aborts when user inputs Q`() { // given givenUserConsoleInputOnReadLine("Q") - var executed = false // when - Authenticator(provider = provider, inputReader = inputReader).connectAndAuthenticate { _, _ -> executed = true } + assertFailsWith { + Authenticator(provider = provider, inputReader = inputReader).connectAndAuthenticate { _, _ -> } + } - // then - assertFalse(executed) - verify(provider, never()).loginPassword(any(), any()) - verify(provider, never()).loginSign(any(), any(), any()) + //then + verify(provider, never()).loginPassword(any(), any()) + verify(provider, never()).loginSign(any(), any(), any()) } @Test @@ -50,7 +51,7 @@ class AuthenticatorTest : TestBase() { // then verify(provider).loginPassword(username, password) - verify(provider, never()).loginSign(any(), any(), any()) + verify(provider, never()).loginSign(any(), any(), any()) assertTrue(executed) } @@ -67,7 +68,7 @@ class AuthenticatorTest : TestBase() { // then verify(provider).loginSign(username, ":cs2:cyb:USB0", null) - verify(provider, never()).loginPassword(any(), any()) + verify(provider, never()).loginPassword(any(), any()) assertTrue(executed) } @@ -86,7 +87,7 @@ class AuthenticatorTest : TestBase() { // then verify(provider, times(3)).loginPassword(username, password) - verify(provider, never()).loginSign(any(), any(), any()) + verify(provider, never()).loginSign(any(), any(), any()) assertTrue(executed) } @@ -98,7 +99,7 @@ class AuthenticatorTest : TestBase() { } private fun givenUserConsoleInputOnReadPassword(input: String) { - whenever(inputReader.readPassword(any())).thenReturn(input) + whenever(inputReader.readPassword(any())).thenReturn(input) } private fun givenUserConsoleInputOnReadLine(input: String) {