Fixes after os -> ent merge to networkManagement (#214)

* Quick fixes

* Fix SignedNodeInfo

Introduce network-management schema changes to reflect that NodeInfos
can have multiple signatures.

* Address Shams comments

Store SignedNodeInfo as a blob for network management tool.
This commit is contained in:
Katarzyna Streich 2017-12-19 21:36:30 +00:00 committed by Shams Asari
parent c171237556
commit 4e80a33dea
15 changed files with 61 additions and 96 deletions

2
.idea/compiler.xml generated
View File

@ -23,6 +23,8 @@
<module name="client_test" target="1.8" /> <module name="client_test" target="1.8" />
<module name="confidential-identities_main" target="1.8" /> <module name="confidential-identities_main" target="1.8" />
<module name="confidential-identities_test" target="1.8" /> <module name="confidential-identities_test" target="1.8" />
<module name="corda-cordform-common_main" target="1.8" />
<module name="corda-cordform-common_test" target="1.8" />
<module name="corda-core_integrationTest" target="1.8" /> <module name="corda-core_integrationTest" target="1.8" />
<module name="corda-core_smokeTest" target="1.8" /> <module name="corda-core_smokeTest" target="1.8" />
<module name="corda-finance_integrationTest" target="1.8" /> <module name="corda-finance_integrationTest" target="1.8" />

View File

@ -8,7 +8,6 @@ import com.r3.corda.networkmanage.common.utils.toX509Certificate
import com.r3.corda.networkmanage.doorman.signer.LocalSigner import com.r3.corda.networkmanage.doorman.signer.LocalSigner
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.SignedData
import net.corda.core.crypto.sign import net.corda.core.crypto.sign
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate import net.corda.core.identity.PartyAndCertificate
@ -97,7 +96,6 @@ class DoormanIntegrationTest {
doorman.close() doorman.close()
} }
@Ignore
@Test @Test
fun `nodeInfo is published to the network map`() { fun `nodeInfo is published to the network map`() {
// Given // Given
@ -149,7 +147,6 @@ class DoormanIntegrationTest {
doReturn(it.certificatesDirectory / "sslkeystore.jks").whenever(it).sslKeystore doReturn(it.certificatesDirectory / "sslkeystore.jks").whenever(it).sslKeystore
doReturn("trustpass").whenever(it).trustStorePassword doReturn("trustpass").whenever(it).trustStorePassword
doReturn("cordacadevpass").whenever(it).keyStorePassword doReturn("cordacadevpass").whenever(it).keyStorePassword
// doReturn(URL("http://${doormanHostAndPort.host}:${doormanHostAndPort.port}")).whenever(it).compatibilityZoneURL
doReturn("iTest@R3.com").whenever(it).emailAddress doReturn("iTest@R3.com").whenever(it).emailAddress
} }
} }

View File

@ -3,6 +3,7 @@ package com.r3.corda.networkmanage.common.persistence
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.SignedData import net.corda.core.crypto.SignedData
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.nodeapi.internal.SignedNodeInfo
import java.security.cert.CertPath import java.security.cert.CertPath
/** /**
@ -19,12 +20,12 @@ interface NodeInfoStorage {
* Retrieve node info together with its signature using nodeInfo's hash * Retrieve node info together with its signature using nodeInfo's hash
* @return [NodeInfo] or null if the node info is not registered. * @return [NodeInfo] or null if the node info is not registered.
*/ */
fun getNodeInfo(nodeInfoHash: SecureHash): SignedData<NodeInfo>? fun getNodeInfo(nodeInfoHash: SecureHash): SignedNodeInfo?
/** /**
* The [nodeInfo] is keyed by the public key, old node info with the same public key will be replaced by the new node info. * The [nodeInfo] is keyed by the public key, old node info with the same public key will be replaced by the new node info.
* @param signedNodeInfo signed node info data to be stored * @param signedNodeInfo signed node info data to be stored
* @return hash for the newly created node info entry * @return hash for the newly created node info entry
*/ */
fun putNodeInfo(signedNodeInfo: SignedData<NodeInfo>): SecureHash fun putNodeInfo(signedNodeInfo: SignedNodeInfo): SecureHash
} }

View File

@ -1,15 +1,13 @@
package com.r3.corda.networkmanage.common.persistence package com.r3.corda.networkmanage.common.persistence
import com.r3.corda.networkmanage.common.persistence.entity.CertificateDataEntity import com.r3.corda.networkmanage.common.persistence.entity.*
import com.r3.corda.networkmanage.common.persistence.entity.CertificateSigningRequestEntity
import com.r3.corda.networkmanage.common.persistence.entity.NodeInfoEntity
import com.r3.corda.networkmanage.common.utils.buildCertPath import com.r3.corda.networkmanage.common.utils.buildCertPath
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.SignedData
import net.corda.core.crypto.sha256 import net.corda.core.crypto.sha256
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.node.NodeInfo
import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.SerializedBytes
import net.corda.core.serialization.serialize
import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.TransactionIsolationLevel import net.corda.nodeapi.internal.persistence.TransactionIsolationLevel
import java.security.cert.CertPath import java.security.cert.CertPath
@ -19,7 +17,7 @@ import java.security.cert.X509Certificate
* Database implementation of the [NetworkMapStorage] interface * Database implementation of the [NetworkMapStorage] interface
*/ */
class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeInfoStorage { class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeInfoStorage {
override fun putNodeInfo(signedNodeInfo: SignedData<NodeInfo>): SecureHash = database.transaction(TransactionIsolationLevel.SERIALIZABLE) { override fun putNodeInfo(signedNodeInfo: SignedNodeInfo): SecureHash = database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
val nodeInfo = signedNodeInfo.verified() val nodeInfo = signedNodeInfo.verified()
val orgName = nodeInfo.legalIdentities.first().name.organisation val orgName = nodeInfo.legalIdentities.first().name.organisation
// TODO: use cert extension to identify NodeCA cert when Ross's work is in. // TODO: use cert extension to identify NodeCA cert when Ross's work is in.
@ -45,23 +43,23 @@ class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeIn
builder.equal(path.get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name), request.certificateSigningRequest) builder.equal(path.get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name), request.certificateSigningRequest)
} }
val hash = signedNodeInfo.raw.hash val hash = signedNodeInfo.raw.hash
val hashedNodeInfo = NodeInfoEntity( val hashedNodeInfo = NodeInfoEntity(
nodeInfoHash = hash.toString(), nodeInfoHash = hash.toString(),
certificateSigningRequest = request.certificateSigningRequest, certificateSigningRequest = request.certificateSigningRequest,
nodeInfoBytes = signedNodeInfo.raw.bytes, signedNodeInfoBytes = signedNodeInfo.serialize().bytes)
signatureBytes = signedNodeInfo.sig.bytes,
signaturePublicKeyBytes = signedNodeInfo.sig.by.encoded,
signaturePublicKeyAlgorithm = signedNodeInfo.sig.by.algorithm)
session.save(hashedNodeInfo) session.save(hashedNodeInfo)
hash hash
} }
override fun getNodeInfo(nodeInfoHash: SecureHash): SignedData<NodeInfo>? = database.transaction { override fun getNodeInfo(nodeInfoHash: SecureHash): SignedNodeInfo? {
return database.transaction {
val nodeInfoEntity = session.find(NodeInfoEntity::class.java, nodeInfoHash.toString()) val nodeInfoEntity = session.find(NodeInfoEntity::class.java, nodeInfoHash.toString())
if (nodeInfoEntity?.signatureBytes == null) { if (nodeInfoEntity == null) {
null null
} else { } else {
SignedData(SerializedBytes(nodeInfoEntity.nodeInfoBytes), nodeInfoEntity.signature()!!) nodeInfoEntity.signedNodeInfo()
}
} }
} }

View File

@ -1,15 +1,13 @@
package com.r3.corda.networkmanage.common.persistence.entity package com.r3.corda.networkmanage.common.persistence.entity
import net.corda.core.crypto.DigitalSignature
import net.corda.core.node.NodeInfo
import net.corda.core.serialization.deserialize import net.corda.core.serialization.deserialize
import java.security.KeyFactory import net.corda.nodeapi.internal.SignedNodeInfo
import java.security.spec.X509EncodedKeySpec
import javax.persistence.* import javax.persistence.*
@Entity @Entity
@Table(name = "node_info") @Table(name = "node_info")
class NodeInfoEntity( class NodeInfoEntity(
// Hash of serialized [NodeInfo] without signatures.
@Id @Id
@Column(name = "node_info_hash", length = 64) @Column(name = "node_info_hash", length = 64)
val nodeInfoHash: String = "", val nodeInfoHash: String = "",
@ -19,53 +17,22 @@ class NodeInfoEntity(
val certificateSigningRequest: CertificateSigningRequestEntity? = null, val certificateSigningRequest: CertificateSigningRequestEntity? = null,
@Lob @Lob
@Column(name = "node_info_bytes") @Column(name = "signed_node_info_bytes")
val nodeInfoBytes: ByteArray, val signedNodeInfoBytes: ByteArray
@Lob
@Column(name = "signature_bytes", nullable = true)
val signatureBytes: ByteArray? = null,
@Lob
@Column(name = "signature_public_key_bytes", nullable = true)
val signaturePublicKeyBytes: ByteArray? = null,
@Lob
@Column(name = "signature_public_key_algorithm", nullable = true)
val signaturePublicKeyAlgorithm: String? = null
) { ) {
/** /**
* Deserializes NodeInfoEntity.nodeInfoBytes into the [NodeInfo] instance * Deserializes NodeInfoEntity.soignedNodeInfoBytes into the [SignedNodeInfo] instance
*/ */
fun nodeInfo() = nodeInfoBytes.deserialize<NodeInfo>() fun signedNodeInfo() = signedNodeInfoBytes.deserialize<SignedNodeInfo>()
/**
* Deserializes NodeInfoEntity.signatureBytes into the [DigitalSignature.WithKey] instance together with its public key
*/
fun signature(): DigitalSignature.WithKey? {
return if (signatureBytes != null && signaturePublicKeyBytes != null && !signaturePublicKeyAlgorithm.isNullOrEmpty()) {
DigitalSignature.WithKey(KeyFactory.getInstance(signaturePublicKeyAlgorithm).generatePublic(X509EncodedKeySpec(signaturePublicKeyBytes)), signatureBytes)
} else {
null
}
}
fun copy(nodeInfoHash: String = this.nodeInfoHash, fun copy(nodeInfoHash: String = this.nodeInfoHash,
certificateSigningRequest: CertificateSigningRequestEntity? = this.certificateSigningRequest, certificateSigningRequest: CertificateSigningRequestEntity? = this.certificateSigningRequest,
nodeInfoBytes: ByteArray = this.nodeInfoBytes, signedNodeInfoBytes: ByteArray = this.signedNodeInfoBytes
signatureBytes: ByteArray? = this.signatureBytes,
signaturePublicKeyBytes: ByteArray? = this.signaturePublicKeyBytes,
signaturePublicKeyAlgorithm: String? = this.signaturePublicKeyAlgorithm
): NodeInfoEntity { ): NodeInfoEntity {
return NodeInfoEntity( return NodeInfoEntity(
nodeInfoHash = nodeInfoHash, nodeInfoHash = nodeInfoHash,
certificateSigningRequest = certificateSigningRequest, certificateSigningRequest = certificateSigningRequest,
nodeInfoBytes = nodeInfoBytes, signedNodeInfoBytes = signedNodeInfoBytes
signatureBytes = signatureBytes,
signaturePublicKeyBytes = signaturePublicKeyBytes,
signaturePublicKeyAlgorithm = signaturePublicKeyAlgorithm
) )
} }
} }

View File

@ -15,6 +15,7 @@ class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private
val nodeInfoHashes = networkMapStorage.getNodeInfoHashes(CertificateStatus.VALID) val nodeInfoHashes = networkMapStorage.getNodeInfoHashes(CertificateStatus.VALID)
val networkParameters = networkMapStorage.getLatestNetworkParameters() val networkParameters = networkMapStorage.getLatestNetworkParameters()
val networkMap = NetworkMap(nodeInfoHashes, networkParameters.serialize().hash) val networkMap = NetworkMap(nodeInfoHashes, networkParameters.serialize().hash)
// We wan only check if the data structure is same.
if (networkMap != currentSignedNetworkMap?.verified(null)) { if (networkMap != currentSignedNetworkMap?.verified(null)) {
val digitalSignature = signer.sign(networkMap.serialize().bytes) val digitalSignature = signer.sign(networkMap.serialize().bytes)
val signedHashedNetworkMap = SignedNetworkMap(networkMap.serialize(), digitalSignature) val signedHashedNetworkMap = SignedNetworkMap(networkMap.serialize(), digitalSignature)

View File

@ -39,7 +39,6 @@ internal data class NotaryConfiguration(private val name: CordaX500Name,
*/ */
internal data class NetworkParametersConfiguration(val minimumPlatformVersion: Int, internal data class NetworkParametersConfiguration(val minimumPlatformVersion: Int,
val notaries: List<NotaryConfiguration>, val notaries: List<NotaryConfiguration>,
val eventHorizonDays: Int,
val maxMessageSize: Int, val maxMessageSize: Int,
val maxTransactionSize: Int) val maxTransactionSize: Int)

View File

@ -12,6 +12,7 @@ import net.corda.core.crypto.SignedData
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.serialization.deserialize import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.network.SignedNetworkMap import net.corda.nodeapi.internal.network.SignedNetworkMap
import java.io.InputStream import java.io.InputStream
import java.security.InvalidKeyException import java.security.InvalidKeyException
@ -44,7 +45,7 @@ class NodeInfoWebService(private val nodeInfoStorage: NodeInfoStorage,
@Path("publish") @Path("publish")
@Consumes(MediaType.APPLICATION_OCTET_STREAM) @Consumes(MediaType.APPLICATION_OCTET_STREAM)
fun registerNode(input: InputStream): Response { fun registerNode(input: InputStream): Response {
val registrationData = input.readBytes().deserialize<SignedData<NodeInfo>>() val registrationData = input.readBytes().deserialize<SignedNodeInfo>()
return try { return try {
// Store the NodeInfo // Store the NodeInfo
nodeInfoStorage.putNodeInfo(registrationData) nodeInfoStorage.putNodeInfo(registrationData)

View File

@ -96,10 +96,7 @@
<column name="node_info_hash" type="VARCHAR(64)"> <column name="node_info_hash" type="VARCHAR(64)">
<constraints nullable="false"/> <constraints nullable="false"/>
</column> </column>
<column name="node_info_bytes" type="BLOB"/> <column name="signed_node_info_bytes" type="BLOB"/>
<column name="signature_bytes" type="BLOB"/>
<column name="signature_public_key_algorithm" type="CLOB"/>
<column name="signature_public_key_bytes" type="BLOB"/>
<column name="certificate_signing_request" type="VARCHAR(64)"> <column name="certificate_signing_request" type="VARCHAR(64)">
<constraints nullable="false"/> <constraints nullable="false"/>
</column> </column>

View File

@ -6,14 +6,12 @@ import com.r3.corda.networkmanage.common.persistence.CertificateSigningRequest
import com.r3.corda.networkmanage.common.persistence.CertificateStatus import com.r3.corda.networkmanage.common.persistence.CertificateStatus
import com.r3.corda.networkmanage.common.persistence.RequestStatus import com.r3.corda.networkmanage.common.persistence.RequestStatus
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.utilities.seconds
import net.corda.nodeapi.internal.network.NetworkParameters import net.corda.nodeapi.internal.network.NetworkParameters
import net.corda.nodeapi.internal.network.NotaryInfo import net.corda.nodeapi.internal.network.NotaryInfo
import net.corda.testing.SerializationEnvironmentRule import net.corda.testing.SerializationEnvironmentRule
import org.bouncycastle.pkcs.PKCS10CertificationRequest import org.bouncycastle.pkcs.PKCS10CertificationRequest
import org.junit.Rule import org.junit.Rule
import java.security.cert.CertPath import java.security.cert.CertPath
import java.time.Duration
import java.time.Instant import java.time.Instant
abstract class TestBase { abstract class TestBase {
@ -54,9 +52,8 @@ abstract class TestBase {
// TODO remove this once testNetworkParameters are updated with default parameters // TODO remove this once testNetworkParameters are updated with default parameters
protected fun createNetworkParameters(minimumPlatformVersion: Int = 1, protected fun createNetworkParameters(minimumPlatformVersion: Int = 1,
notaries: List<NotaryInfo> = emptyList(), notaries: List<NotaryInfo> = emptyList(),
eventHorizon: Duration = 1.seconds, maxMessageSize: Int = 10485760,
maxMessageSize: Int = 0, maxTransactionSize: Int = 40000,
maxTransactionSize: Int = 0,
modifiedTime: Instant = Instant.now(), modifiedTime: Instant = Instant.now(),
epoch: Int = 1): NetworkParameters { epoch: Int = 1): NetworkParameters {
return NetworkParameters( return NetworkParameters(

View File

@ -5,7 +5,6 @@ import com.r3.corda.networkmanage.common.utils.buildCertPath
import com.r3.corda.networkmanage.common.utils.toX509Certificate import com.r3.corda.networkmanage.common.utils.toX509Certificate
import com.r3.corda.networkmanage.common.utils.withCert import com.r3.corda.networkmanage.common.utils.withCert
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SignedData
import net.corda.core.crypto.sign import net.corda.core.crypto.sign
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate import net.corda.core.identity.PartyAndCertificate
@ -13,6 +12,7 @@ import net.corda.core.internal.cert
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.network.NetworkMap import net.corda.nodeapi.internal.network.NetworkMap
@ -64,7 +64,7 @@ class DBNetworkMapStorageTest : TestBase() {
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L) val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
// Put signed node info data // Put signed node info data
val nodeInfoBytes = nodeInfo.serialize() val nodeInfoBytes = nodeInfo.serialize()
val nodeInfoHash = nodeInfoStorage.putNodeInfo(SignedData(nodeInfoBytes, keyPair.sign(nodeInfoBytes))) val nodeInfoHash = nodeInfoStorage.putNodeInfo(SignedNodeInfo(nodeInfoBytes, listOf(keyPair.sign(nodeInfoBytes))))
// Create network parameters // Create network parameters
val networkParametersHash = networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList())) val networkParametersHash = networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList()))
@ -131,15 +131,16 @@ class DBNetworkMapStorageTest : TestBase() {
val requestIdA = requestStorage.saveRequest(createRequest(organisationA).first) val requestIdA = requestStorage.saveRequest(createRequest(organisationA).first)
requestStorage.markRequestTicketCreated(requestIdA) requestStorage.markRequestTicketCreated(requestIdA)
requestStorage.approveRequest(requestIdA, "TestUser") requestStorage.approveRequest(requestIdA, "TestUser")
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val keyPairA = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val clientCertA = X509Utilities.createCertificate(CertificateType.NODE_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisationA, locality = "London", country = "GB"), keyPair.public) val clientCertA = X509Utilities.createCertificate(CertificateType.NODE_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisationA, locality = "London", country = "GB"), keyPairA.public)
val certPathA = buildCertPath(clientCertA.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate()) val certPathA = buildCertPath(clientCertA.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
requestStorage.putCertificatePath(requestIdA, certPathA, emptyList()) requestStorage.putCertificatePath(requestIdA, certPathA, emptyList())
val organisationB = "TestB" val organisationB = "TestB"
val requestIdB = requestStorage.saveRequest(createRequest(organisationB).first) val requestIdB = requestStorage.saveRequest(createRequest(organisationB).first)
requestStorage.markRequestTicketCreated(requestIdB) requestStorage.markRequestTicketCreated(requestIdB)
requestStorage.approveRequest(requestIdB, "TestUser") requestStorage.approveRequest(requestIdB, "TestUser")
val clientCertB = X509Utilities.createCertificate(CertificateType.NODE_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisationB, locality = "London", country = "GB"), Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME).public) val keyPairB = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val clientCertB = X509Utilities.createCertificate(CertificateType.NODE_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisationB, locality = "London", country = "GB"), keyPairB.public)
val certPathB = buildCertPath(clientCertB.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate()) val certPathB = buildCertPath(clientCertB.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
requestStorage.putCertificatePath(requestIdB, certPathB, emptyList()) requestStorage.putCertificatePath(requestIdB, certPathB, emptyList())
val nodeInfoA = NodeInfo(listOf(NetworkHostAndPort("my.companyA.com", 1234)), listOf(PartyAndCertificate(certPathA)), 1, serial = 1L) val nodeInfoA = NodeInfo(listOf(NetworkHostAndPort("my.companyA.com", 1234)), listOf(PartyAndCertificate(certPathA)), 1, serial = 1L)
@ -147,14 +148,14 @@ class DBNetworkMapStorageTest : TestBase() {
// Put signed node info data // Put signed node info data
val nodeInfoABytes = nodeInfoA.serialize() val nodeInfoABytes = nodeInfoA.serialize()
val nodeInfoBBytes = nodeInfoB.serialize() val nodeInfoBBytes = nodeInfoB.serialize()
val nodeInfoHashA = nodeInfoStorage.putNodeInfo(SignedData(nodeInfoABytes, keyPair.sign(nodeInfoABytes))) val nodeInfoHashA = nodeInfoStorage.putNodeInfo(SignedNodeInfo(nodeInfoABytes, listOf(keyPairA.sign(nodeInfoABytes))))
val nodeInfoHashB = nodeInfoStorage.putNodeInfo(SignedData(nodeInfoBBytes, keyPair.sign(nodeInfoBBytes))) val nodeInfoHashB = nodeInfoStorage.putNodeInfo(SignedNodeInfo(nodeInfoBBytes, listOf(keyPairB.sign(nodeInfoBBytes))))
// Create network parameters // Create network parameters
val networkParametersHash = networkMapStorage.saveNetworkParameters(createNetworkParameters()) val networkParametersHash = networkMapStorage.saveNetworkParameters(createNetworkParameters())
val networkMap = NetworkMap(listOf(nodeInfoHashA), networkParametersHash) val networkMap = NetworkMap(listOf(nodeInfoHashA), networkParametersHash)
val serializedNetworkMap = networkMap.serialize() val serializedNetworkMap = networkMap.serialize()
val signatureData = keyPair.sign(serializedNetworkMap).withCert(clientCertA.cert) val signatureData = keyPairA.sign(serializedNetworkMap).withCert(clientCertA.cert)
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData) val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
// Sign network map // Sign network map

View File

@ -6,17 +6,16 @@ import com.r3.corda.networkmanage.common.utils.hashString
import com.r3.corda.networkmanage.common.utils.toX509Certificate import com.r3.corda.networkmanage.common.utils.toX509Certificate
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.SignedData
import net.corda.core.crypto.sign import net.corda.core.crypto.sign
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -77,15 +76,16 @@ class PersitenceNodeInfoStorageTest : TestBase() {
val requestIdA = requestStorage.saveRequest(createRequest(organisationA).first) val requestIdA = requestStorage.saveRequest(createRequest(organisationA).first)
requestStorage.markRequestTicketCreated(requestIdA) requestStorage.markRequestTicketCreated(requestIdA)
requestStorage.approveRequest(requestIdA, "TestUser") requestStorage.approveRequest(requestIdA, "TestUser")
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val keyPairA = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val clientCertA = X509Utilities.createCertificate(CertificateType.NODE_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisationA, locality = "London", country = "GB"), keyPair.public) val clientCertA = X509Utilities.createCertificate(CertificateType.NODE_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisationA, locality = "London", country = "GB"), keyPairA.public)
val certPathA = buildCertPath(clientCertA.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate()) val certPathA = buildCertPath(clientCertA.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
requestStorage.putCertificatePath(requestIdA, certPathA, emptyList()) requestStorage.putCertificatePath(requestIdA, certPathA, emptyList())
val organisationB = "TestB" val organisationB = "TestB"
val requestIdB = requestStorage.saveRequest(createRequest(organisationB).first) val requestIdB = requestStorage.saveRequest(createRequest(organisationB).first)
requestStorage.markRequestTicketCreated(requestIdB) requestStorage.markRequestTicketCreated(requestIdB)
requestStorage.approveRequest(requestIdB, "TestUser") requestStorage.approveRequest(requestIdB, "TestUser")
val clientCertB = X509Utilities.createCertificate(CertificateType.NODE_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisationB, locality = "London", country = "GB"), Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME).public) val keyPairB = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val clientCertB = X509Utilities.createCertificate(CertificateType.NODE_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisationB, locality = "London", country = "GB"), keyPairB.public)
val certPathB = buildCertPath(clientCertB.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate()) val certPathB = buildCertPath(clientCertB.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
requestStorage.putCertificatePath(requestIdB, certPathB, emptyList()) requestStorage.putCertificatePath(requestIdB, certPathB, emptyList())
val nodeInfoA = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPathA)), 1, serial = 1L) val nodeInfoA = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPathA)), 1, serial = 1L)
@ -94,8 +94,8 @@ class PersitenceNodeInfoStorageTest : TestBase() {
// Put signed node info data // Put signed node info data
val nodeInfoABytes = nodeInfoA.serialize() val nodeInfoABytes = nodeInfoA.serialize()
val nodeInfoBBytes = nodeInfoB.serialize() val nodeInfoBBytes = nodeInfoB.serialize()
nodeInfoStorage.putNodeInfo(SignedData(nodeInfoABytes, keyPair.sign(nodeInfoABytes))) nodeInfoStorage.putNodeInfo(SignedNodeInfo(nodeInfoABytes, listOf(keyPairA.sign(nodeInfoABytes))))
nodeInfoStorage.putNodeInfo(SignedData(nodeInfoBBytes, keyPair.sign(nodeInfoBBytes))) nodeInfoStorage.putNodeInfo(SignedNodeInfo(nodeInfoBBytes, listOf(keyPairB.sign(nodeInfoBBytes))))
// when // when
val persistedNodeInfoA = nodeInfoStorage.getNodeInfo(nodeInfoABytes.hash) val persistedNodeInfoA = nodeInfoStorage.getNodeInfo(nodeInfoABytes.hash)
@ -123,12 +123,12 @@ class PersitenceNodeInfoStorageTest : TestBase() {
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L) val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
val nodeInfoSamePubKey = NodeInfo(listOf(NetworkHostAndPort("my.company2.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L) val nodeInfoSamePubKey = NodeInfo(listOf(NetworkHostAndPort("my.company2.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
val nodeInfoBytes = nodeInfo.serialize() val nodeInfoBytes = nodeInfo.serialize()
val nodeInfoHash = nodeInfoStorage.putNodeInfo(SignedData(nodeInfoBytes, keyPair.sign(nodeInfoBytes))) val nodeInfoHash = nodeInfoStorage.putNodeInfo(SignedNodeInfo(nodeInfoBytes, listOf(keyPair.sign(nodeInfoBytes))))
assertEquals(nodeInfo, nodeInfoStorage.getNodeInfo(nodeInfoHash)?.verified()) assertEquals(nodeInfo, nodeInfoStorage.getNodeInfo(nodeInfoHash)?.verified())
val nodeInfoSamePubKeyBytes = nodeInfoSamePubKey.serialize() val nodeInfoSamePubKeyBytes = nodeInfoSamePubKey.serialize()
// This should replace the node info. // This should replace the node info.
nodeInfoStorage.putNodeInfo(SignedData(nodeInfoSamePubKeyBytes, keyPair.sign(nodeInfoSamePubKeyBytes))) nodeInfoStorage.putNodeInfo(SignedNodeInfo(nodeInfoSamePubKeyBytes, listOf(keyPair.sign(nodeInfoSamePubKeyBytes))))
// Old node info should be removed. // Old node info should be removed.
assertNull(nodeInfoStorage.getNodeInfo(nodeInfoHash)) assertNull(nodeInfoStorage.getNodeInfo(nodeInfoHash))
@ -153,12 +153,12 @@ class PersitenceNodeInfoStorageTest : TestBase() {
val signature = keyPair.sign(nodeInfoBytes) val signature = keyPair.sign(nodeInfoBytes)
// when // when
val nodeInfoHash = nodeInfoStorage.putNodeInfo(SignedData(nodeInfoBytes, signature)) val nodeInfoHash = nodeInfoStorage.putNodeInfo(SignedNodeInfo(nodeInfoBytes, listOf(signature)))
// then // then
val persistedNodeInfo = nodeInfoStorage.getNodeInfo(nodeInfoHash) val persistedNodeInfo = nodeInfoStorage.getNodeInfo(nodeInfoHash)
assertNotNull(persistedNodeInfo) assertNotNull(persistedNodeInfo)
assertEquals(nodeInfo, persistedNodeInfo!!.verified()) assertEquals(nodeInfo, persistedNodeInfo!!.verified())
assertEquals(signature, persistedNodeInfo.sig) assertEquals(signature, persistedNodeInfo.signatures.firstOrNull())
} }
} }

View File

@ -19,6 +19,7 @@ import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.network.NetworkMap import net.corda.nodeapi.internal.network.NetworkMap
@ -64,7 +65,7 @@ class NodeInfoWebServiceTest {
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(nodeInfoStorage, mock(), testNetwotkMapConfig)).use { NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(nodeInfoStorage, mock(), testNetwotkMapConfig)).use {
it.start() it.start()
val registerURL = URL("http://${it.hostAndPort}/${NodeInfoWebService.NETWORK_MAP_PATH}/publish") val registerURL = URL("http://${it.hostAndPort}/${NodeInfoWebService.NETWORK_MAP_PATH}/publish")
val nodeInfoAndSignature = SignedData(nodeInfo.serialize(), digitalSignature).serialize().bytes val nodeInfoAndSignature = SignedNodeInfo(nodeInfo.serialize(), listOf(digitalSignature)).serialize().bytes
// Post node info and signature to doorman, this should pass without any exception. // Post node info and signature to doorman, this should pass without any exception.
doPost(registerURL, nodeInfoAndSignature) doPost(registerURL, nodeInfoAndSignature)
} }
@ -97,14 +98,14 @@ class NodeInfoWebServiceTest {
val nodeInfoStorage: NodeInfoStorage = mock { val nodeInfoStorage: NodeInfoStorage = mock {
val serializedNodeInfo = nodeInfo.serialize() val serializedNodeInfo = nodeInfo.serialize()
on { getNodeInfo(nodeInfoHash) }.thenReturn(SignedData(serializedNodeInfo, keyPair.sign(serializedNodeInfo))) on { getNodeInfo(nodeInfoHash) }.thenReturn(SignedNodeInfo(serializedNodeInfo, listOf(keyPair.sign(serializedNodeInfo))))
} }
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(nodeInfoStorage, mock(), testNetwotkMapConfig)).use { NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(nodeInfoStorage, mock(), testNetwotkMapConfig)).use {
it.start() it.start()
val nodeInfoURL = URL("http://${it.hostAndPort}/${NodeInfoWebService.NETWORK_MAP_PATH}/node-info/$nodeInfoHash") val nodeInfoURL = URL("http://${it.hostAndPort}/${NodeInfoWebService.NETWORK_MAP_PATH}/node-info/$nodeInfoHash")
val conn = nodeInfoURL.openConnection() val conn = nodeInfoURL.openConnection()
val nodeInfoResponse = conn.inputStream.readBytes().deserialize<SignedData<NodeInfo>>() val nodeInfoResponse = conn.inputStream.readBytes().deserialize<SignedNodeInfo>()
verify(nodeInfoStorage, times(1)).getNodeInfo(nodeInfoHash) verify(nodeInfoStorage, times(1)).getNodeInfo(nodeInfoHash)
assertEquals(nodeInfo, nodeInfoResponse.verified()) assertEquals(nodeInfo, nodeInfoResponse.verified())

View File

@ -70,8 +70,8 @@ class SignedNetworkMap(val raw: SerializedBytes<NetworkMap>, val signature: Digi
@Throws(SignatureException::class, CertPathValidatorException::class) @Throws(SignatureException::class, CertPathValidatorException::class)
fun verified(trustedRoot: X509Certificate?): NetworkMap { fun verified(trustedRoot: X509Certificate?): NetworkMap {
signature.by.publicKey.verify(raw.bytes, signature) signature.by.publicKey.verify(raw.bytes, signature)
// Assume network map cert is under the default trust root.
if (trustedRoot != null) { if (trustedRoot != null) {
// Assume network map cert is under the default trust root.
X509Utilities.validateCertificateChain(trustedRoot, signature.by, trustedRoot) X509Utilities.validateCertificateChain(trustedRoot, signature.by, trustedRoot)
} }
return raw.deserialize() return raw.deserialize()

View File

@ -31,6 +31,9 @@ include 'perftestcordapp'
['test-common', 'test-utils', 'smoke-test-utils', 'node-driver'].each { ['test-common', 'test-utils', 'smoke-test-utils', 'node-driver'].each {
project(":$it").projectDir = new File("$settingsDir/testing/$it") project(":$it").projectDir = new File("$settingsDir/testing/$it")
} }
include 'network-management'
include 'network-management:capsule'
include 'network-management:capsule-hsm'
include 'tools:jmeter' include 'tools:jmeter'
include 'tools:explorer' include 'tools:explorer'
include 'tools:explorer:capsule' include 'tools:explorer:capsule'