mirror of
https://github.com/corda/corda.git
synced 2024-12-26 08:01:09 +00:00
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
This commit is contained in:
parent
60fca0bf16
commit
b3ca36132f
4
.idea/compiler.xml
generated
4
.idea/compiler.xml
generated
@ -15,6 +15,8 @@
|
||||
<module name="business-network-demo_integrationTest" target="1.8" />
|
||||
<module name="business-network-demo_main" target="1.8" />
|
||||
<module name="business-network-demo_test" target="1.8" />
|
||||
<module name="capsule-hsm_main" target="1.8" />
|
||||
<module name="capsule-hsm_test" target="1.8" />
|
||||
<module name="client_main" target="1.8" />
|
||||
<module name="client_test" target="1.8" />
|
||||
<module name="confidential-identities_main" target="1.8" />
|
||||
@ -172,4 +174,4 @@
|
||||
<module name="webserver_test" target="1.8" />
|
||||
</bytecodeTargetLevel>
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
@ -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"
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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<CertificateStatus>): List<SecureHash>
|
||||
fun getNodeInfoHashes(certificateStatus: CertificateStatus): List<SecureHash>
|
||||
|
||||
/**
|
||||
* 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<SecureHash>
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -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<NetworkMap>().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<SecureHash> = database.transaction {
|
||||
val builder = session.criteriaBuilder
|
||||
val query = builder.createQuery(String::class.java).run {
|
||||
from(NodeInfoEntity::class.java).run {
|
||||
select(get<String>(NodeInfoEntity::nodeInfoHash.name))
|
||||
.where(builder.equal(get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name)
|
||||
.get<CertificateDataEntity>(CertificateSigningRequestEntity::certificateData.name)
|
||||
.get<CertificateStatus>(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<CertificateStatus>): List<SecureHash> = 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<SecureHash> = 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<ByteArray>(NodeInfoEntity::networkMap.name)),
|
||||
builder.isNotNull(get<ByteArray>(NodeInfoEntity::signatureBytes.name))))
|
||||
}
|
||||
}
|
||||
session.createQuery(query).resultList.map { SecureHash.parse(it.nodeInfoHash) }
|
||||
}
|
||||
|
||||
private fun getCurrentNetworkMapEntity(hint: Pair<String, Any>): 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<ByteArray?>(NetworkMapEntity::signatureBytes.name)))
|
||||
where(builder.isNotNull(get<ByteArray?>(NetworkMapEntity::signature.name)))
|
||||
orderBy(builder.desc(get<String>(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<String>(NetworkParametersEntity::parametersHash.name), parameterHash)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates Hibernate query hint for pulling [NetworkParametersEntity] when querying for [NetworkMapEntity]
|
||||
*/
|
||||
private fun getNetworkMapWithParametersHint(session: Session): Pair<String, Any> {
|
||||
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<String, Any> {
|
||||
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<String, Any> {
|
||||
val graph = session.createEntityGraph(NetworkMapEntity::class.java)
|
||||
graph.addAttributeNodes(NetworkMapEntity::nodeInfoList.name)
|
||||
graph.addAttributeNodes(NetworkMapEntity::parameters.name)
|
||||
return QueryHints.HINT_LOADGRAPH to graph
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<NodeInfoEntity> = 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)
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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<String>, 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)
|
||||
}
|
||||
}
|
||||
|
@ -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?
|
||||
}
|
||||
fun sign(data: ByteArray): DigitalSignatureWithCert
|
||||
}
|
||||
|
||||
class AuthenticationException : Exception()
|
||||
|
@ -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)
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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<Certificate>) : Signer {
|
||||
class LocalSigner(private val caKeyPair: KeyPair, private val caCertPath: Array<X509Certificate>) : 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())
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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<String>) -> Unit) {
|
||||
try {
|
||||
fun <T : Any> connectAndAuthenticate(block: (CryptoServerProvider, List<String>) -> T): T {
|
||||
return try {
|
||||
val authenticated = mutableListOf<String>()
|
||||
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(
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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<SignedNetworkMap>().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<SignedNetworkMap>().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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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<SignedNetworkMap>()
|
||||
val signedNetworkMap = conn.inputStream.readBytes().deserialize<SignedNetworkMap>()
|
||||
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<SignedData<NodeInfo>>()
|
||||
verify(nodeInfoStorage, times(1)).getNodeInfo(nodeInfoHash)
|
||||
|
@ -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<AuthenticationException> {
|
||||
Authenticator(provider = provider, inputReader = inputReader).connectAndAuthenticate { _, _ -> }
|
||||
}
|
||||
|
||||
// then
|
||||
assertFalse(executed)
|
||||
verify(provider, never()).loginPassword(any<String>(), any<String>())
|
||||
verify(provider, never()).loginSign(any<String>(), any<String>(), any<String>())
|
||||
//then
|
||||
verify(provider, never()).loginPassword(any(), any<String>())
|
||||
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<String>(), any<String>(), any<String>())
|
||||
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<String>(), any<String>())
|
||||
verify(provider, never()).loginPassword(any(), any<String>())
|
||||
assertTrue(executed)
|
||||
}
|
||||
|
||||
@ -86,7 +87,7 @@ class AuthenticatorTest : TestBase() {
|
||||
|
||||
// then
|
||||
verify(provider, times(3)).loginPassword(username, password)
|
||||
verify(provider, never()).loginSign(any<String>(), any<String>(), any<String>())
|
||||
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<String>())).thenReturn(input)
|
||||
whenever(inputReader.readPassword(any())).thenReturn(input)
|
||||
}
|
||||
|
||||
private fun givenUserConsoleInputOnReadLine(input: String) {
|
||||
|
Loading…
Reference in New Issue
Block a user