network_map table references the network_parameters table (ENT-1524). (#567)

This commit is contained in:
Shams Asari 2018-03-16 10:57:30 +00:00 committed by GitHub
parent 2a898658c2
commit 78b2bc7549
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 304 additions and 278 deletions

View File

@ -388,10 +388,16 @@ val CordaX500Name.x500Name: X500Name
val CordaX500Name.Companion.unspecifiedCountry val CordaX500Name.Companion.unspecifiedCountry
get() = "ZZ" get() = "ZZ"
fun <T : Any> T.signWithCert(privateKey: PrivateKey, certificate: X509Certificate): SignedDataWithCert<T> { inline fun <T : Any> T.signWithCert(signer: (SerializedBytes<T>) -> DigitalSignatureWithCert): SignedDataWithCert<T> {
val serialised = serialize() val serialised = serialize()
val signature = Crypto.doSign(privateKey, serialised.bytes) return SignedDataWithCert(serialised, signer(serialised))
return SignedDataWithCert(serialised, DigitalSignatureWithCert(certificate, signature)) }
fun <T : Any> T.signWithCert(privateKey: PrivateKey, certificate: X509Certificate): SignedDataWithCert<T> {
return signWithCert {
val signature = Crypto.doSign(privateKey, it.bytes)
DigitalSignatureWithCert(certificate, signature)
}
} }
inline fun <T : Any> SerializedBytes<T>.sign(signer: (SerializedBytes<T>) -> DigitalSignature.WithKey): SignedData<T> { inline fun <T : Any> SerializedBytes<T>.sign(signer: (SerializedBytes<T>) -> DigitalSignature.WithKey): SignedData<T> {

View File

@ -165,9 +165,7 @@ class HsmSigningServiceTest : HsmBaseTest() {
networkMapSigner.signNetworkMap() networkMapSigner.signNetworkMap()
// then // then
val signedNetworkMap = networkMapStorage.getCurrentNetworkMap() val persistedNetworkMap = networkMapStorage.getActiveNetworkMap()!!.toSignedNetworkMap().verified()
assertNotNull(signedNetworkMap)
val persistedNetworkMap = signedNetworkMap!!.verified()
assertEquals(networkMapParameters.serialize().hash, persistedNetworkMap.networkParameterHash) assertEquals(networkMapParameters.serialize().hash, persistedNetworkMap.networkParameterHash)
assertThat(persistedNetworkMap.nodeInfoHashes).isEmpty() assertThat(persistedNetworkMap.nodeInfoHashes).isEmpty()
} }

View File

@ -10,11 +10,13 @@
package com.r3.corda.networkmanage.common.persistence 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.persistence.entity.NodeInfoEntity
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.internal.DigitalSignatureWithCert import net.corda.core.internal.DigitalSignatureWithCert
import net.corda.core.node.NetworkParameters import net.corda.core.node.NetworkParameters
import net.corda.nodeapi.internal.network.SignedNetworkMap import net.corda.nodeapi.internal.network.NetworkMapAndSigned
import net.corda.nodeapi.internal.network.SignedNetworkParameters import net.corda.nodeapi.internal.network.SignedNetworkParameters
/** /**
@ -22,47 +24,37 @@ import net.corda.nodeapi.internal.network.SignedNetworkParameters
*/ */
interface NetworkMapStorage { interface NetworkMapStorage {
/** /**
* Retrieves current network map. Current in this context means the one that has been most recently signed. * Returns the active network map, or null
* @return current network map
*/ */
fun getCurrentNetworkMap(): SignedNetworkMap? fun getActiveNetworkMap(): NetworkMapEntity?
/**
* Persist the new active network map, replacing any existing network map.
*/
fun saveNewActiveNetworkMap(networkMapAndSigned: NetworkMapAndSigned)
/** /**
* Retrieves node info hashes where [NodeInfoEntity.isCurrent] is true and the certificate status is [CertificateStatus.VALID] * Retrieves node info hashes where [NodeInfoEntity.isCurrent] is true and the certificate status is [CertificateStatus.VALID]
*
* @return list of current and valid node info hashes.
*/ */
fun getActiveNodeInfoHashes(): List<SecureHash> fun getActiveNodeInfoHashes(): List<SecureHash>
/**
* Persists a new instance of the signed network map.
* @param signedNetworkMap encapsulates all the information needed for persisting current network map state.
*/
fun saveNetworkMap(signedNetworkMap: SignedNetworkMap)
/** /**
* Retrieve the signed with certificate network parameters by their hash. The hash is that of the underlying * Retrieve the signed with certificate network parameters by their hash. The hash is that of the underlying
* [NetworkParameters] object and not the `SignedWithCert<NetworkParameters>` object that's returned. * [NetworkParameters] object and not the [SignedNetworkParameters] object that's returned.
* @return signed network parameters corresponding to the given hash or null if it does not exist (parameters don't exist or they haven't been signed yet) * @return signed network parameters corresponding to the given hash or null if it does not exist (parameters don't exist or they haven't been signed yet)
*/ */
fun getSignedNetworkParameters(hash: SecureHash): SignedNetworkParameters? fun getSignedNetworkParameters(hash: SecureHash): SignedNetworkParameters?
/**
* Retrieve the network parameters of the current network map, or null if there's no network map.
*/
// TODO: Remove this method. We should get the "current" network parameter by using the the hash in the network map and use the [getSignedNetworkParameters] method.
fun getNetworkParametersOfNetworkMap(): SignedNetworkParameters?
/** /**
* Persists given network parameters with signature if provided. * Persists given network parameters with signature if provided.
* @return hash corresponding to newly created network parameters entry * @return hash corresponding to newly created network parameters entry
*/ */
fun saveNetworkParameters(networkParameters: NetworkParameters, sig: DigitalSignatureWithCert?): SecureHash fun saveNetworkParameters(networkParameters: NetworkParameters, signature: DigitalSignatureWithCert?): SecureHash
/** /**
* Retrieves the latest (i.e. most recently inserted) network parameters * Retrieves the latest (i.e. most recently inserted) network parameters
* Note that they may not have been signed up yet. * Note that they may not have been signed up yet.
* @return latest network parameters * @return latest network parameters
*/ */
fun getLatestNetworkParameters(): NetworkParameters? fun getLatestNetworkParameters(): NetworkParametersEntity?
} }

View File

@ -18,23 +18,24 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.nodeapi.internal.persistence.DatabaseTransaction import net.corda.nodeapi.internal.persistence.DatabaseTransaction
import net.corda.nodeapi.internal.persistence.SchemaMigration import net.corda.nodeapi.internal.persistence.SchemaMigration
import org.hibernate.query.Query
import java.util.* import java.util.*
import javax.persistence.LockModeType import javax.persistence.LockModeType
import javax.persistence.criteria.CriteriaBuilder import javax.persistence.criteria.CriteriaBuilder
import javax.persistence.criteria.Path import javax.persistence.criteria.Path
import javax.persistence.criteria.Predicate import javax.persistence.criteria.Predicate
inline fun <reified T> DatabaseTransaction.singleEntityWhere(predicate: (CriteriaBuilder, Path<T>) -> Predicate): T? { inline fun <reified T> DatabaseTransaction.uniqueEntityWhere(predicate: (CriteriaBuilder, Path<T>) -> Predicate): T? {
return getEntitiesWhere(predicate).firstOrNull() return entitiesWhere(predicate).setMaxResults(1).uniqueResult()
} }
inline fun <reified T> DatabaseTransaction.getEntitiesWhere(predicate: (CriteriaBuilder, Path<T>) -> Predicate): List<T> { inline fun <reified T> DatabaseTransaction.entitiesWhere(predicate: (CriteriaBuilder, Path<T>) -> Predicate): Query<T> {
val builder = session.criteriaBuilder val builder = session.criteriaBuilder
val criteriaQuery = builder.createQuery(T::class.java) val criteriaQuery = builder.createQuery(T::class.java)
val query = criteriaQuery.from(T::class.java).run { val query = criteriaQuery.from(T::class.java).run {
criteriaQuery.where(predicate(builder, this)) criteriaQuery.where(predicate(builder, this))
} }
return session.createQuery(query).setLockMode(LockModeType.PESSIMISTIC_WRITE).resultList return session.createQuery(query).setLockMode(LockModeType.PESSIMISTIC_WRITE)
} }
inline fun <reified T> DatabaseTransaction.deleteEntity(predicate: (CriteriaBuilder, Path<T>) -> Predicate): Int { inline fun <reified T> DatabaseTransaction.deleteEntity(predicate: (CriteriaBuilder, Path<T>) -> Predicate): Int {

View File

@ -40,7 +40,7 @@ class PersistentCertificateRevocationListStorage(private val database: CordaPers
} }
private fun revokeCertificate(certificateSerialNumber: BigInteger, time: Instant, transaction: DatabaseTransaction) { private fun revokeCertificate(certificateSerialNumber: BigInteger, time: Instant, transaction: DatabaseTransaction) {
val revocation = transaction.singleEntityWhere<CertificateRevocationRequestEntity> { builder, path -> val revocation = transaction.uniqueEntityWhere<CertificateRevocationRequestEntity> { builder, path ->
builder.equal(path.get<BigInteger>(CertificateRevocationRequestEntity::certificateSerialNumber.name), certificateSerialNumber) builder.equal(path.get<BigInteger>(CertificateRevocationRequestEntity::certificateSerialNumber.name), certificateSerialNumber)
} }
revocation ?: throw IllegalStateException("The certificate revocation request for $certificateSerialNumber does not exist") revocation ?: throw IllegalStateException("The certificate revocation request for $certificateSerialNumber does not exist")

View File

@ -13,7 +13,7 @@ class PersistentCertificateRevocationRequestStorage(private val database: CordaP
override fun saveRevocationRequest(certificateSerialNumber: BigInteger, reason: CRLReason, reporter: String): String { override fun saveRevocationRequest(certificateSerialNumber: BigInteger, reason: CRLReason, reporter: String): String {
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) { return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
// Check if there is an entry for the given certificate serial number // Check if there is an entry for the given certificate serial number
val revocation = singleEntityWhere<CertificateRevocationRequestEntity> { builder, path -> val revocation = uniqueEntityWhere<CertificateRevocationRequestEntity> { builder, path ->
val serialNumberEqual = builder.equal(path.get<BigInteger>(CertificateRevocationRequestEntity::certificateSerialNumber.name), certificateSerialNumber) val serialNumberEqual = builder.equal(path.get<BigInteger>(CertificateRevocationRequestEntity::certificateSerialNumber.name), certificateSerialNumber)
val statusNotEqualRejected = builder.notEqual(path.get<RequestStatus>(CertificateRevocationRequestEntity::status.name), RequestStatus.REJECTED) val statusNotEqualRejected = builder.notEqual(path.get<RequestStatus>(CertificateRevocationRequestEntity::status.name), RequestStatus.REJECTED)
builder.and(serialNumberEqual, statusNotEqualRejected) builder.and(serialNumberEqual, statusNotEqualRejected)
@ -21,7 +21,7 @@ class PersistentCertificateRevocationRequestStorage(private val database: CordaP
if (revocation != null) { if (revocation != null) {
revocation.requestId revocation.requestId
} else { } else {
val certificateData = singleEntityWhere<CertificateDataEntity> { builder, path -> val certificateData = uniqueEntityWhere<CertificateDataEntity> { builder, path ->
val serialNumberEqual = builder.equal(path.get<BigInteger>(CertificateDataEntity::certificateSerialNumber.name), certificateSerialNumber) val serialNumberEqual = builder.equal(path.get<BigInteger>(CertificateDataEntity::certificateSerialNumber.name), certificateSerialNumber)
val statusEqualValid = builder.equal(path.get<CertificateStatus>(CertificateDataEntity::certificateStatus.name), CertificateStatus.VALID) val statusEqualValid = builder.equal(path.get<CertificateStatus>(CertificateDataEntity::certificateStatus.name), CertificateStatus.VALID)
builder.and(serialNumberEqual, statusEqualValid) builder.and(serialNumberEqual, statusEqualValid)
@ -90,7 +90,7 @@ class PersistentCertificateRevocationRequestStorage(private val database: CordaP
} }
private fun getRevocationRequestEntity(requestId: String): CertificateRevocationRequestEntity? = database.transaction { private fun getRevocationRequestEntity(requestId: String): CertificateRevocationRequestEntity? = database.transaction {
singleEntityWhere { builder, path -> uniqueEntityWhere { builder, path ->
builder.equal(path.get<String>(CertificateRevocationRequestEntity::requestId.name), requestId) builder.equal(path.get<String>(CertificateRevocationRequestEntity::requestId.name), requestId)
} }
} }

View File

@ -38,7 +38,7 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
override fun putCertificatePath(requestId: String, certPath: CertPath, signedBy: String) { override fun putCertificatePath(requestId: String, certPath: CertPath, signedBy: String) {
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) { return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
val request = singleEntityWhere<CertificateSigningRequestEntity> { builder, path -> val request = uniqueEntityWhere<CertificateSigningRequestEntity> { builder, path ->
val requestIdEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::requestId.name), requestId) val requestIdEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::requestId.name), requestId)
val statusEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::status.name), RequestStatus.APPROVED) val statusEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::status.name), RequestStatus.APPROVED)
builder.and(requestIdEq, statusEq) builder.and(requestIdEq, statusEq)
@ -89,7 +89,7 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
private fun DatabaseTransaction.findRequest(requestId: String, private fun DatabaseTransaction.findRequest(requestId: String,
requestStatus: RequestStatus? = null): CertificateSigningRequestEntity? { requestStatus: RequestStatus? = null): CertificateSigningRequestEntity? {
return singleEntityWhere { builder, path -> return uniqueEntityWhere { builder, path ->
val idClause = builder.equal(path.get<String>(CertificateSigningRequestEntity::requestId.name), requestId) val idClause = builder.equal(path.get<String>(CertificateSigningRequestEntity::requestId.name), requestId)
if (requestStatus == null) { if (requestStatus == null) {
idClause idClause

View File

@ -12,48 +12,54 @@ package com.r3.corda.networkmanage.common.persistence
import com.r3.corda.networkmanage.common.persistence.entity.* import com.r3.corda.networkmanage.common.persistence.entity.*
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.sha256
import net.corda.core.internal.DigitalSignatureWithCert import net.corda.core.internal.DigitalSignatureWithCert
import net.corda.core.node.NetworkParameters import net.corda.core.node.NetworkParameters
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.nodeapi.internal.network.SignedNetworkMap import net.corda.nodeapi.internal.network.NetworkMapAndSigned
import net.corda.nodeapi.internal.network.SignedNetworkParameters import net.corda.nodeapi.internal.network.SignedNetworkParameters
import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseTransaction
/** /**
* Database implementation of the [NetworkMapStorage] interface * Database implementation of the [NetworkMapStorage] interface
*/ */
class PersistentNetworkMapStorage(private val database: CordaPersistence) : NetworkMapStorage { class PersistentNetworkMapStorage(private val database: CordaPersistence) : NetworkMapStorage {
override fun getCurrentNetworkMap(): SignedNetworkMap? { override fun getActiveNetworkMap(): NetworkMapEntity? {
return database.transaction { return database.transaction {
getCurrentNetworkMapEntity()?.toSignedNetworkMap() val builder = session.criteriaBuilder
} val query = builder.createQuery(NetworkMapEntity::class.java).run {
} from(NetworkMapEntity::class.java).run {
orderBy(builder.desc(get<Long>(NetworkMapEntity::version.name)))
override fun getNetworkParametersOfNetworkMap(): SignedNetworkParameters? { }
return database.transaction {
getCurrentNetworkMapEntity()?.let {
val netParamsHash = it.toNetworkMap().networkParameterHash
getSignedNetworkParameters(netParamsHash) ?:
throw IllegalStateException("Current network map is pointing to network parameters that do not exist: $netParamsHash")
} }
// We want the latest signed entry
session.createQuery(query).setMaxResults(1).uniqueResult()
} }
} }
override fun saveNetworkMap(signedNetworkMap: SignedNetworkMap) { override fun saveNewActiveNetworkMap(networkMapAndSigned: NetworkMapAndSigned) {
val (networkMap, signedNetworkMap) = networkMapAndSigned
database.transaction { database.transaction {
val networkMapEntity = NetworkMapEntity( val networkParametersEntity = checkNotNull(getNetworkParametersEntity(networkMap.networkParameterHash)) {
networkMap = signedNetworkMap.raw.bytes, "Network parameters ${networkMap.networkParameterHash} must be first persisted"
}
check(networkParametersEntity.isSigned) {
"Network parameters ${networkMap.networkParameterHash} are not signed"
}
session.save(NetworkMapEntity(
networkMapBytes = signedNetworkMap.raw.bytes,
signature = signedNetworkMap.sig.bytes, signature = signedNetworkMap.sig.bytes,
certificate = signedNetworkMap.sig.by.encoded certificate = signedNetworkMap.sig.by.encoded,
) networkParameters = networkParametersEntity
session.save(networkMapEntity) ))
} }
} }
override fun getSignedNetworkParameters(hash: SecureHash): SignedNetworkParameters? { override fun getSignedNetworkParameters(hash: SecureHash): SignedNetworkParameters? {
return getNetworkParametersEntity(hash.toString())?.let { return database.transaction {
if (it.isSigned) it.toSignedNetworkParameters() else null getNetworkParametersEntity(hash)?.let {
if (it.isSigned) it.toSignedNetworkParameters() else null
}
} }
} }
@ -65,6 +71,8 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
val certStatusExpression = get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name) val certStatusExpression = get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name)
.get<CertificateDataEntity>(CertificateSigningRequestEntity::certificateData.name) .get<CertificateDataEntity>(CertificateSigningRequestEntity::certificateData.name)
.get<CertificateStatus>(CertificateDataEntity::certificateStatus.name) .get<CertificateStatus>(CertificateDataEntity::certificateStatus.name)
// TODO When revoking certs, all node-infos that point to it must be made non-current. Then this check
// isn't needed.
val certStatusEq = builder.equal(certStatusExpression, CertificateStatus.VALID) val certStatusEq = builder.equal(certStatusExpression, CertificateStatus.VALID)
val isCurrentNodeInfo = builder.isTrue(get<Boolean>(NodeInfoEntity::isCurrent.name)) val isCurrentNodeInfo = builder.isTrue(get<Boolean>(NodeInfoEntity::isCurrent.name))
select(get<String>(NodeInfoEntity::nodeInfoHash.name)).where(builder.and(certStatusEq, isCurrentNodeInfo)) select(get<String>(NodeInfoEntity::nodeInfoHash.name)).where(builder.and(certStatusEq, isCurrentNodeInfo))
@ -74,21 +82,21 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
} }
} }
override fun saveNetworkParameters(networkParameters: NetworkParameters, sig: DigitalSignatureWithCert?): SecureHash { override fun saveNetworkParameters(networkParameters: NetworkParameters, signature: DigitalSignatureWithCert?): SecureHash {
return database.transaction { val serialised = networkParameters.serialize()
val bytes = networkParameters.serialize().bytes val hash = serialised.hash
val hash = bytes.sha256() database.transaction {
session.saveOrUpdate(NetworkParametersEntity( session.saveOrUpdate(NetworkParametersEntity(
parametersBytes = bytes, parametersBytes = serialised.bytes,
parametersHash = hash.toString(), parametersHash = hash.toString(),
signature = sig?.bytes, signature = signature?.bytes,
certificate = sig?.by?.encoded certificate = signature?.by?.encoded
)) ))
hash
} }
return hash
} }
override fun getLatestNetworkParameters(): NetworkParameters? { override fun getLatestNetworkParameters(): NetworkParametersEntity? {
return database.transaction { return database.transaction {
val query = session.criteriaBuilder.run { val query = session.criteriaBuilder.run {
createQuery(NetworkParametersEntity::class.java).run { createQuery(NetworkParametersEntity::class.java).run {
@ -98,30 +106,13 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
} }
} }
// We just want the last entry // We just want the last entry
session.createQuery(query).setMaxResults(1).uniqueResult()?.toNetworkParameters() session.createQuery(query).setMaxResults(1).uniqueResult()
} }
} }
private fun getCurrentNetworkMapEntity(): NetworkMapEntity? { private fun DatabaseTransaction.getNetworkParametersEntity(hash: SecureHash): NetworkParametersEntity? {
return database.transaction { return uniqueEntityWhere { builder, path ->
val builder = session.criteriaBuilder builder.equal(path.get<String>(NetworkParametersEntity::parametersHash.name), hash.toString())
val query = builder.createQuery(NetworkMapEntity::class.java).run {
from(NetworkMapEntity::class.java).run {
// TODO a limit of 1 since we only need the first result
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).resultList.firstOrNull()
}
}
private fun getNetworkParametersEntity(parameterHash: String): NetworkParametersEntity? {
return database.transaction {
singleEntityWhere { builder, path ->
builder.equal(path.get<String>(NetworkParametersEntity::parametersHash.name), parameterHash)
}
} }
} }
} }

View File

@ -43,12 +43,13 @@ class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeIn
} }
// Update any [NodeInfoEntity] instance for this CSR as not current. // Update any [NodeInfoEntity] instance for this CSR as not current.
val existingNodeInfo = getEntitiesWhere<NodeInfoEntity> { builder, path -> entitiesWhere<NodeInfoEntity> { builder, path ->
val requestEq = builder.equal(path.get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name), request) val requestEq = builder.equal(path.get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name), request)
val isCurrent = builder.isTrue(path.get<Boolean>(NodeInfoEntity::isCurrent.name)) val isCurrent = builder.isTrue(path.get<Boolean>(NodeInfoEntity::isCurrent.name))
builder.and(requestEq, isCurrent) builder.and(requestEq, isCurrent)
}.resultStream.use { existingNodeInfos ->
existingNodeInfos.forEach { session.merge(it.copy(isCurrent = false)) }
} }
existingNodeInfo.forEach { session.merge(it.copy(isCurrent = false)) }
val hash = signedNodeInfo.raw.hash val hash = signedNodeInfo.raw.hash
val hashedNodeInfo = NodeInfoEntity( val hashedNodeInfo = NodeInfoEntity(
@ -75,7 +76,7 @@ class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeIn
} }
private fun DatabaseTransaction.getSignedRequestByPublicHash(publicKeyHash: SecureHash): CertificateSigningRequestEntity? { private fun DatabaseTransaction.getSignedRequestByPublicHash(publicKeyHash: SecureHash): CertificateSigningRequestEntity? {
return singleEntityWhere { builder, path -> return uniqueEntityWhere { builder, path ->
val publicKeyEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::publicKeyHash.name), publicKeyHash.toString()) val publicKeyEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::publicKeyHash.name), publicKeyHash.toString())
val statusEq = builder.equal(path.get<RequestStatus>(CertificateSigningRequestEntity::status.name), RequestStatus.DONE) val statusEq = builder.equal(path.get<RequestStatus>(CertificateSigningRequestEntity::status.name), RequestStatus.DONE)
builder.and(publicKeyEq, statusEq) builder.and(publicKeyEq, statusEq)

View File

@ -26,22 +26,26 @@ class NetworkMapEntity(
val version: Long? = null, val version: Long? = null,
@Lob @Lob
@Column(name = "serialized_network_map") @Column(name = "serialized_network_map", nullable = false)
val networkMap: ByteArray, val networkMapBytes: ByteArray,
@Lob @Lob
@Column(name = "signature") @Column(name = "signature", nullable = false)
val signature: ByteArray, val signature: ByteArray,
@Lob @Lob
@Column(name = "certificate") @Column(name = "certificate", nullable = false)
val certificate: ByteArray val certificate: ByteArray,
@ManyToOne(optional = false, fetch = FetchType.EAGER)
@JoinColumn(name = "network_parameters")
val networkParameters: NetworkParametersEntity
) { ) {
fun toNetworkMap(): NetworkMap = networkMap.deserialize() fun toNetworkMap(): NetworkMap = networkMapBytes.deserialize()
fun toSignedNetworkMap(): SignedNetworkMap { fun toSignedNetworkMap(): SignedNetworkMap {
return SignedNetworkMap( return SignedNetworkMap(
SerializedBytes(networkMap), SerializedBytes(networkMapBytes),
DigitalSignatureWithCert(X509CertificateFactory().generateCertificate(certificate.inputStream()), signature) DigitalSignatureWithCert(X509CertificateFactory().generateCertificate(certificate.inputStream()), signature)
) )
} }

View File

@ -31,7 +31,7 @@ class NetworkParametersEntity(
val created: Instant = Instant.now(), val created: Instant = Instant.now(),
@Lob @Lob
@Column(name = "parameters_bytes") @Column(name = "parameters_bytes", nullable = false)
val parametersBytes: ByteArray, val parametersBytes: ByteArray,
// Both of the fields below are nullable, because of the way we sign network map data. NetworkParameters can be // Both of the fields below are nullable, because of the way we sign network map data. NetworkParameters can be

View File

@ -11,11 +11,12 @@
package com.r3.corda.networkmanage.common.signer package com.r3.corda.networkmanage.common.signer
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
import net.corda.core.crypto.SecureHash
import net.corda.core.node.NetworkParameters import net.corda.core.node.NetworkParameters
import net.corda.core.serialization.serialize
import net.corda.core.utilities.contextLogger import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.debug
import net.corda.nodeapi.internal.network.NetworkMap import net.corda.nodeapi.internal.network.NetworkMap
import net.corda.nodeapi.internal.network.SignedNetworkMap import net.corda.nodeapi.internal.network.NetworkMapAndSigned
class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private val signer: Signer) { class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private val signer: Signer) {
private companion object { private companion object {
@ -28,41 +29,45 @@ class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private
fun signNetworkMap() { fun signNetworkMap() {
// TODO There is no network parameters update process in place yet. We assume that latest parameters are to be used // TODO There is no network parameters update process in place yet. We assume that latest parameters are to be used
// in current network map. // in current network map.
val latestNetworkParameters = networkMapStorage.getLatestNetworkParameters() val latestNetParamsEntity = networkMapStorage.getLatestNetworkParameters()
if (latestNetworkParameters == null) { if (latestNetParamsEntity == null) {
logger.debug("No network parameters present") logger.warn("No network parameters present")
return return
} }
logger.debug("Fetching current network map parameters...")
val currentNetworkParameters = networkMapStorage.getNetworkParametersOfNetworkMap() val latestNetParams = latestNetParamsEntity.toNetworkParameters()
logger.debug("Retrieved network map parameters: $currentNetworkParameters") logger.debug { "Latest network parameters: $latestNetParams" }
if (currentNetworkParameters?.verified() != latestNetworkParameters) {
persistSignedNetworkParameters(latestNetworkParameters) if (!latestNetParamsEntity.isSigned) {
signAndPersistNetworkParameters(latestNetParams)
} else { } else {
logger.debug("Network map parameters up-to-date. Skipping signing.") logger.debug("Network parameters are already signed")
} }
logger.debug("Fetching current network map...")
val currentSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
logger.debug("Fetching node info hashes with VALID certificates...")
val nodeInfoHashes = networkMapStorage.getActiveNodeInfoHashes() val nodeInfoHashes = networkMapStorage.getActiveNodeInfoHashes()
logger.debug("Retrieved node info hashes: $nodeInfoHashes") logger.debug { "Active node-info hashes:\n${nodeInfoHashes.joinToString("\n")}" }
val newNetworkMap = NetworkMap(nodeInfoHashes, latestNetworkParameters.serialize().hash, null)
val serialisedNetworkMap = newNetworkMap.serialize() val currentNetworkMap = networkMapStorage.getActiveNetworkMap()?.toNetworkMap()
if (serialisedNetworkMap != currentSignedNetworkMap?.raw) { if (currentNetworkMap != null) {
logger.info("Signing a new network map: $newNetworkMap") logger.debug { "Current network map: $currentNetworkMap" }
logger.debug("Creating a new signed network map: ${serialisedNetworkMap.hash}")
val newSignedNetworkMap = SignedNetworkMap(serialisedNetworkMap, signer.signBytes(serialisedNetworkMap.bytes))
networkMapStorage.saveNetworkMap(newSignedNetworkMap)
logger.debug("Signed network map saved")
} else { } else {
logger.debug("Current network map is up-to-date. Skipping signing.") logger.info("There is currently no network map")
}
val newNetworkMap = NetworkMap(nodeInfoHashes, SecureHash.parse(latestNetParamsEntity.parametersHash), null)
logger.debug { "Potential new network map: $newNetworkMap" }
if (currentNetworkMap != newNetworkMap) {
val netNetworkMapAndSigned = NetworkMapAndSigned(newNetworkMap) { signer.signBytes(it.bytes) }
networkMapStorage.saveNewActiveNetworkMap(netNetworkMapAndSigned)
logger.info("Signed new network map: $newNetworkMap")
} else {
logger.debug("Current network map is up-to-date")
} }
} }
fun persistSignedNetworkParameters(networkParameters: NetworkParameters) { fun signAndPersistNetworkParameters(networkParameters: NetworkParameters) {
logger.info("Signing and persisting network parameters: $networkParameters") networkMapStorage.saveNetworkParameters(networkParameters, signer.signObject(networkParameters).sig)
val digitalSignature = signer.signObject(networkParameters).sig logger.info("Signed network parameters: $networkParameters")
networkMapStorage.saveNetworkParameters(networkParameters, digitalSignature)
logger.info("Signed network map parameters saved.")
} }
} }

View File

@ -59,9 +59,9 @@ class NetworkManagementServer : Closeable {
val localNetworkMapSigner = signer?.let { NetworkMapSigner(networkMapStorage, it) } val localNetworkMapSigner = signer?.let { NetworkMapSigner(networkMapStorage, it) }
newNetworkParameters?.let { newNetworkParameters?.let {
val netParamsOfNetworkMap = networkMapStorage.getNetworkParametersOfNetworkMap() val netParamsOfNetworkMap = networkMapStorage.getActiveNetworkMap()?.networkParameters
if (netParamsOfNetworkMap == null) { if (netParamsOfNetworkMap == null) {
localNetworkMapSigner?.persistSignedNetworkParameters(it) ?: networkMapStorage.saveNetworkParameters(it, null) localNetworkMapSigner?.signAndPersistNetworkParameters(it) ?: networkMapStorage.saveNetworkParameters(it, null)
} else { } else {
throw UnsupportedOperationException("Network parameters already exist. Updating them is not supported yet.") throw UnsupportedOperationException("Network parameters already exist. Updating them is not supported yet.")
} }

View File

@ -52,11 +52,12 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
private val networkMapCache: LoadingCache<Boolean, CachedData> = Caffeine.newBuilder() private val networkMapCache: LoadingCache<Boolean, CachedData> = Caffeine.newBuilder()
.expireAfterWrite(config.cacheTimeout, TimeUnit.MILLISECONDS) .expireAfterWrite(config.cacheTimeout, TimeUnit.MILLISECONDS)
.build { _ -> .build {
networkMapStorage.getCurrentNetworkMap()?.let { networkMapStorage.getActiveNetworkMap()?.let {
val networkMap = it.verified() logger.info("Re-publishing network map")
val networkParameters = networkMapStorage.getSignedNetworkParameters(networkMap.networkParameterHash)?.verified() val networkMap = it.toNetworkMap()
CachedData(it, networkMap.nodeInfoHashes.toSet(), networkParameters) val signedNetworkMap = it.toSignedNetworkMap()
CachedData(signedNetworkMap, networkMap.nodeInfoHashes.toSet(), it.networkParameters.toNetworkParameters())
} }
} }
@ -67,7 +68,7 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
private val currentSignedNetworkMap: SignedNetworkMap? get() = networkMapCache.get(true)?.signedNetworkMap private val currentSignedNetworkMap: SignedNetworkMap? get() = networkMapCache.get(true)?.signedNetworkMap
private val currentNodeInfoHashes: Set<SecureHash> get() = networkMapCache.get(true)?.nodeInfoHashes ?: emptySet() private val currentNodeInfoHashes: Set<SecureHash> get() = networkMapCache.get(true)?.nodeInfoHashes ?: emptySet()
private val currentNetworkParameters: NetworkParameters? get() = networkMapCache.get(true)?.currentNetworkParameter private val currentNetworkParameters: NetworkParameters? get() = networkMapCache.get(true)?.networkParameters
@POST @POST
@Path("publish") @Path("publish")
@ -153,6 +154,7 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
class NetworkMapNotInitialisedException(message: String?) : Exception(message) class NetworkMapNotInitialisedException(message: String?) : Exception(message)
class InvalidPlatformVersionException(message: String?) : Exception(message) class InvalidPlatformVersionException(message: String?) : Exception(message)
private data class CachedData(val signedNetworkMap: SignedNetworkMap, val nodeInfoHashes: Set<SecureHash>, val currentNetworkParameter: NetworkParameters?) private data class CachedData(val signedNetworkMap: SignedNetworkMap,
val nodeInfoHashes: Set<SecureHash>,
val networkParameters: NetworkParameters)
} }

View File

@ -80,9 +80,18 @@
<column name="version" type="BIGINT"> <column name="version" type="BIGINT">
<constraints nullable="false"/> <constraints nullable="false"/>
</column> </column>
<column name="certificate" type="BLOB"/> <column name="certificate" type="BLOB">
<column name="serialized_network_map" type="BLOB"/> <constraints nullable="false"/>
<column name="signature" type="BLOB"/> </column>
<column name="serialized_network_map" type="BLOB">
<constraints nullable="false"/>
</column>
<column name="signature" type="BLOB">
<constraints nullable="false"/>
</column>
<column name="network_parameters" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
</createTable> </createTable>
</changeSet> </changeSet>
<changeSet author="R3.Corda" id="1520338500424-6"> <changeSet author="R3.Corda" id="1520338500424-6">
@ -92,7 +101,9 @@
</column> </column>
<column name="certificate" type="BLOB"/> <column name="certificate" type="BLOB"/>
<column name="created" type="TIMESTAMP"/> <column name="created" type="TIMESTAMP"/>
<column name="parameters_bytes" type="BLOB"/> <column name="parameters_bytes" type="BLOB">
<constraints nullable="false"/>
</column>
<column name="signature" type="BLOB"/> <column name="signature" type="BLOB"/>
</createTable> </createTable>
</changeSet> </changeSet>
@ -299,4 +310,9 @@
constraintName="FK_CSR_PN" constraintName="FK_CSR_PN"
referencedColumnNames="id" referencedTableName="private_network"/> referencedColumnNames="id" referencedTableName="private_network"/>
</changeSet> </changeSet>
<changeSet author="R3.Corda" id="1520338500424-38">
<addForeignKeyConstraint baseColumnNames="network_parameters" baseTableName="network_map"
constraintName="FK_NM_NP"
referencedColumnNames="hash" referencedTableName="network_parameters"/>
</changeSet>
</databaseChangeLog> </databaseChangeLog>

View File

@ -0,0 +1,40 @@
package com.r3.corda.networkmanage
import com.r3.corda.networkmanage.common.persistence.entity.NetworkMapEntity
import com.r3.corda.networkmanage.common.persistence.entity.NetworkParametersEntity
import net.corda.core.crypto.SecureHash
import net.corda.core.node.NetworkParameters
import net.corda.nodeapi.internal.createDevNetworkMapCa
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.network.NetworkMap
import net.corda.testing.common.internal.testNetworkParameters
fun createNetworkParametersEntity(signingCertAndKeyPair: CertificateAndKeyPair = createDevNetworkMapCa(),
networkParameters: NetworkParameters = testNetworkParameters()): NetworkParametersEntity {
val signedNetParams = signingCertAndKeyPair.sign(networkParameters)
return NetworkParametersEntity(
parametersHash = signedNetParams.raw.hash.toString(),
parametersBytes = signedNetParams.raw.bytes,
signature = signedNetParams.sig.bytes,
certificate = signedNetParams.sig.by.encoded
)
}
fun createNetworkMapEntity(signingCertAndKeyPair: CertificateAndKeyPair = createDevNetworkMapCa(),
netParamsEntity: NetworkParametersEntity,
nodeInfoHashes: List<SecureHash> = emptyList()): NetworkMapEntity {
val signedNetMap = signingCertAndKeyPair.sign(NetworkMap(nodeInfoHashes, SecureHash.parse(netParamsEntity.parametersHash), null))
return NetworkMapEntity(
networkMapBytes = signedNetMap.raw.bytes,
signature = signedNetMap.sig.bytes,
certificate = signedNetMap.sig.by.encoded,
networkParameters = netParamsEntity
)
}
fun createNetworkMapEntity(signingCertAndKeyPair: CertificateAndKeyPair = createDevNetworkMapCa(),
networkParameters: NetworkParameters = testNetworkParameters(),
nodeInfoHashes: List<SecureHash> = emptyList()): NetworkMapEntity {
val netParamsEntity = createNetworkParametersEntity(signingCertAndKeyPair, networkParameters)
return createNetworkMapEntity(signingCertAndKeyPair, netParamsEntity, nodeInfoHashes)
}

View File

@ -11,10 +11,12 @@
package com.r3.corda.networkmanage.common.persistence package com.r3.corda.networkmanage.common.persistence
import com.r3.corda.networkmanage.TestBase import com.r3.corda.networkmanage.TestBase
import net.corda.core.internal.signWithCert import com.r3.corda.networkmanage.common.persistence.entity.NodeInfoEntity
import net.corda.core.crypto.SecureHash
import net.corda.nodeapi.internal.createDevNetworkMapCa import net.corda.nodeapi.internal.createDevNetworkMapCa
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.network.NetworkMap import net.corda.nodeapi.internal.network.NetworkMap
import net.corda.nodeapi.internal.network.NetworkMapAndSigned
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig import net.corda.nodeapi.internal.persistence.DatabaseConfig
@ -26,7 +28,6 @@ import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import kotlin.test.assertEquals
class PersistentNetworkMapStorageTest : TestBase() { class PersistentNetworkMapStorageTest : TestBase() {
private lateinit var persistence: CordaPersistence private lateinit var persistence: CordaPersistence
@ -35,13 +36,13 @@ class PersistentNetworkMapStorageTest : TestBase() {
private lateinit var requestStorage: PersistentCertificateSigningRequestStorage private lateinit var requestStorage: PersistentCertificateSigningRequestStorage
private lateinit var rootCaCert: X509Certificate private lateinit var rootCaCert: X509Certificate
private lateinit var networkMapCa: CertificateAndKeyPair private lateinit var networkMapCertAndKeyPair: CertificateAndKeyPair
@Before @Before
fun startDb() { fun startDb() {
val (rootCa) = createDevIntermediateCaCertPath() val (rootCa) = createDevIntermediateCaCertPath()
rootCaCert = rootCa.certificate rootCaCert = rootCa.certificate
networkMapCa = createDevNetworkMapCa(rootCa) networkMapCertAndKeyPair = createDevNetworkMapCa(rootCa)
persistence = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true)) persistence = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true))
networkMapStorage = PersistentNetworkMapStorage(persistence) networkMapStorage = PersistentNetworkMapStorage(persistence)
nodeInfoStorage = PersistentNodeInfoStorage(persistence) nodeInfoStorage = PersistentNodeInfoStorage(persistence)
@ -54,74 +55,52 @@ class PersistentNetworkMapStorageTest : TestBase() {
} }
@Test @Test
fun `saveNetworkMap and saveNetworkParameters create current network map and parameters`() { fun `saveNetworkParameters and then saveNewActiveNetworkMap creates the active network map`() {
// given // given
// Create node info. // Create node info.
val (signedNodeInfo) = createValidSignedNodeInfo("Test", requestStorage) val (signedNodeInfo) = createValidSignedNodeInfo("Test", requestStorage)
val nodeInfoHash = nodeInfoStorage.putNodeInfo(signedNodeInfo) val nodeInfoHash = nodeInfoStorage.putNodeInfo(signedNodeInfo)
val networkParameters = testNetworkParameters(emptyList())
val parametersSignature = networkParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate).sig
// Create network parameters // Create network parameters
val networkParametersHash = networkMapStorage.saveNetworkParameters(networkParameters, parametersSignature) val networkParameters = testNetworkParameters(maxTransactionSize = 1234567)
val networkParametersSig = networkMapCertAndKeyPair.sign(networkParameters).sig
val networkParametersHash = networkMapStorage.saveNetworkParameters(networkParameters, networkParametersSig)
val networkMap = NetworkMap(listOf(nodeInfoHash), networkParametersHash, null) val networkMap = NetworkMap(listOf(nodeInfoHash), networkParametersHash, null)
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate) val networkMapAndSigned = NetworkMapAndSigned(networkMap) { networkMapCertAndKeyPair.sign(networkMap).sig }
// when // when
networkMapStorage.saveNetworkMap(signedNetworkMap) networkMapStorage.saveNewActiveNetworkMap(networkMapAndSigned)
// then // then
val persistedSignedNetworkMap = networkMapStorage.getCurrentNetworkMap() val activeNetworkMapEntity = networkMapStorage.getActiveNetworkMap()!!
val persistedSignedParameters = networkMapStorage.getNetworkParametersOfNetworkMap() val activeSignedNetworkMap = activeNetworkMapEntity.toSignedNetworkMap()
val activeNetworkMap = activeSignedNetworkMap.verifiedNetworkMapCert(rootCaCert)
val activeNetworkParametersEntity = activeNetworkMapEntity.networkParameters
val activeSignedNetworkParameters = activeNetworkParametersEntity.toSignedNetworkParameters()
val activeNetworkParameters = activeSignedNetworkParameters.verifiedNetworkMapCert(rootCaCert)
assertEquals(networkParameters, persistedSignedParameters?.verifiedNetworkMapCert(rootCaCert)) assertThat(activeNetworkMap).isEqualTo(networkMap)
assertEquals(parametersSignature, persistedSignedParameters?.sig) assertThat(activeSignedNetworkMap.sig).isEqualTo(networkMapAndSigned.signed.sig)
assertEquals(signedNetworkMap.sig, persistedSignedNetworkMap?.sig) assertThat(activeNetworkParameters).isEqualTo(networkParameters)
assertEquals(signedNetworkMap.verifiedNetworkMapCert(rootCaCert), persistedSignedNetworkMap?.verifiedNetworkMapCert(rootCaCert)) assertThat(activeSignedNetworkParameters.sig).isEqualTo(networkParametersSig)
assertEquals(signedNetworkMap.verifiedNetworkMapCert(rootCaCert).networkParameterHash, persistedSignedParameters?.raw?.hash) assertThat(SecureHash.parse(activeNetworkParametersEntity.parametersHash))
.isEqualTo(activeNetworkMap.networkParameterHash)
.isEqualTo(networkParametersHash)
} }
@Test @Test
fun `getLatestNetworkParameters returns last inserted`() { fun `getLatestNetworkParameters returns last inserted`() {
val params1 = testNetworkParameters(emptyList(), minimumPlatformVersion = 1) val params1 = testNetworkParameters(minimumPlatformVersion = 1)
val params2 = testNetworkParameters(emptyList(), minimumPlatformVersion = 2) val params2 = testNetworkParameters(minimumPlatformVersion = 2)
// given networkMapStorage.saveNetworkParameters(params1, networkMapCertAndKeyPair.sign(params1).sig)
networkMapStorage.saveNetworkParameters(params1, params1.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate).sig)
// We may have not signed them yet. // We may have not signed them yet.
networkMapStorage.saveNetworkParameters(params2, null) networkMapStorage.saveNetworkParameters(params2, null)
// when assertThat(networkMapStorage.getLatestNetworkParameters()?.toNetworkParameters()).isEqualTo(params2)
val latest = networkMapStorage.getLatestNetworkParameters()?.minimumPlatformVersion
// then
assertEquals(2, latest)
} }
@Test @Test
fun `getNetworkParametersOfNetworkMap returns current network map parameters`() { fun `getValidNodeInfoHashes returns only for current node-infos`() {
// given
// Create network parameters
val testParameters1 = testNetworkParameters(emptyList())
val networkParametersHash = networkMapStorage.saveNetworkParameters(testParameters1, testParameters1.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate).sig)
// Create empty network map
// Sign network map making it current network map
val networkMap = NetworkMap(emptyList(), networkParametersHash, null)
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
networkMapStorage.saveNetworkMap(signedNetworkMap)
// Create new network parameters
val testParameters2 = testNetworkParameters(emptyList(), minimumPlatformVersion = 2)
networkMapStorage.saveNetworkParameters(testParameters2, testParameters2.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate).sig)
// when
val result = networkMapStorage.getNetworkParametersOfNetworkMap()?.verifiedNetworkMapCert(rootCaCert)
// then
assertEquals(1, result?.minimumPlatformVersion)
}
@Test
fun `getValidNodeInfoHashes returns only valid and signed node info hashes`() {
// given // given
// Create node infos. // Create node infos.
val (signedNodeInfoA) = createValidSignedNodeInfo("TestA", requestStorage) val (signedNodeInfoA) = createValidSignedNodeInfo("TestA", requestStorage)
@ -131,19 +110,15 @@ class PersistentNetworkMapStorageTest : TestBase() {
val nodeInfoHashA = nodeInfoStorage.putNodeInfo(signedNodeInfoA) val nodeInfoHashA = nodeInfoStorage.putNodeInfo(signedNodeInfoA)
val nodeInfoHashB = nodeInfoStorage.putNodeInfo(signedNodeInfoB) val nodeInfoHashB = nodeInfoStorage.putNodeInfo(signedNodeInfoB)
// Create network parameters persistence.transaction {
val testParameters = testNetworkParameters(emptyList()) val entity = session.find(NodeInfoEntity::class.java, nodeInfoHashA.toString())
val networkParametersHash = networkMapStorage.saveNetworkParameters(testParameters, testParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate).sig) session.merge(entity.copy(isCurrent = false))
val networkMap = NetworkMap(listOf(nodeInfoHashA), networkParametersHash, null) }
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
// Sign network map
networkMapStorage.saveNetworkMap(signedNetworkMap)
// when // when
val validNodeInfoHash = networkMapStorage.getActiveNodeInfoHashes() val validNodeInfoHashes = networkMapStorage.getActiveNodeInfoHashes()
// then // then
assertThat(validNodeInfoHash).containsOnly(nodeInfoHashA, nodeInfoHashB) assertThat(validNodeInfoHashes).containsOnly(nodeInfoHashB)
} }
} }

View File

@ -13,18 +13,16 @@ package com.r3.corda.networkmanage.common.signer
import com.nhaarman.mockito_kotlin.* import com.nhaarman.mockito_kotlin.*
import com.r3.corda.networkmanage.TestBase import com.r3.corda.networkmanage.TestBase
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
import com.r3.corda.networkmanage.createNetworkMapEntity
import com.r3.corda.networkmanage.createNetworkParametersEntity
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.sha256
import net.corda.core.internal.DigitalSignatureWithCert import net.corda.core.internal.DigitalSignatureWithCert
import net.corda.core.internal.signWithCert
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.nodeapi.internal.createDevNetworkMapCa import net.corda.nodeapi.internal.createDevNetworkMapCa
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.network.NetworkMap import net.corda.nodeapi.internal.network.NetworkMapAndSigned
import net.corda.nodeapi.internal.network.SignedNetworkMap
import net.corda.nodeapi.internal.network.SignedNetworkParameters import net.corda.nodeapi.internal.network.SignedNetworkParameters
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.internal.createDevIntermediateCaCertPath import net.corda.testing.internal.createDevIntermediateCaCertPath
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
@ -39,13 +37,13 @@ class NetworkMapSignerTest : TestBase() {
private lateinit var networkMapSigner: NetworkMapSigner private lateinit var networkMapSigner: NetworkMapSigner
private lateinit var rootCaCert: X509Certificate private lateinit var rootCaCert: X509Certificate
private lateinit var networkMapCa: CertificateAndKeyPair private lateinit var signingCertAndKeyPair: CertificateAndKeyPair
@Before @Before
fun setUp() { fun setUp() {
val (rootCa) = createDevIntermediateCaCertPath() val (rootCa) = createDevIntermediateCaCertPath()
rootCaCert = rootCa.certificate rootCaCert = rootCa.certificate
networkMapCa = createDevNetworkMapCa(rootCa) signingCertAndKeyPair = createDevNetworkMapCa(rootCa)
signer = mock() signer = mock()
networkMapStorage = mock() networkMapStorage = mock()
networkMapSigner = NetworkMapSigner(networkMapStorage, signer) networkMapSigner = NetworkMapSigner(networkMapStorage, signer)
@ -54,20 +52,20 @@ class NetworkMapSignerTest : TestBase() {
@Test @Test
fun `signNetworkMap builds and signs network map and network parameters`() { fun `signNetworkMap builds and signs network map and network parameters`() {
// given // given
val signedNodeInfoHashes = listOf(SecureHash.randomSHA256(), SecureHash.randomSHA256()) val nodeInfoHashes = listOf(SecureHash.randomSHA256(), SecureHash.randomSHA256())
val currentParameters = testNetworkParameters(emptyList(), minimumPlatformVersion = 1) val activeNetParams = testNetworkParameters(minimumPlatformVersion = 1)
val latestNetworkParameters = testNetworkParameters(emptyList(), minimumPlatformVersion = 2) val latestNetParams = testNetworkParameters(minimumPlatformVersion = 2)
val networkMap = NetworkMap(signedNodeInfoHashes, currentParameters.serialize().hash, null) val activeNetParamsEntity = createNetworkParametersEntity(signingCertAndKeyPair, activeNetParams)
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate) val latestNetParamsEntity = createNetworkParametersEntity(signingCertAndKeyPair, latestNetParams)
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(signedNetworkMap) val netMapEntity = createNetworkMapEntity(signingCertAndKeyPair, activeNetParamsEntity, nodeInfoHashes)
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(signedNodeInfoHashes) whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(latestNetParamsEntity)
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(latestNetworkParameters) whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(nodeInfoHashes)
whenever(networkMapStorage.getNetworkParametersOfNetworkMap()).thenReturn(currentParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)) whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(netMapEntity)
whenever(signer.signBytes(any())).then { whenever(signer.signBytes(any())).then {
DigitalSignatureWithCert(networkMapCa.certificate, Crypto.doSign(networkMapCa.keyPair.private, it.arguments[0] as ByteArray)) DigitalSignatureWithCert(signingCertAndKeyPair.certificate, Crypto.doSign(signingCertAndKeyPair.keyPair.private, it.arguments[0] as ByteArray))
} }
whenever(signer.signObject(latestNetworkParameters)).then { whenever(signer.signObject(latestNetParams)).then {
val serialised = latestNetworkParameters.serialize() val serialised = latestNetParams.serialize()
SignedNetworkParameters(serialised, signer.signBytes(serialised.bytes)) SignedNetworkParameters(serialised, signer.signBytes(serialised.bytes))
} }
@ -78,48 +76,43 @@ class NetworkMapSignerTest : TestBase() {
// Verify networkMapStorage calls // Verify networkMapStorage calls
verify(networkMapStorage).getActiveNodeInfoHashes() verify(networkMapStorage).getActiveNodeInfoHashes()
verify(networkMapStorage).getLatestNetworkParameters() verify(networkMapStorage).getLatestNetworkParameters()
verify(networkMapStorage).getNetworkParametersOfNetworkMap() argumentCaptor<NetworkMapAndSigned>().apply {
argumentCaptor<SignedNetworkMap>().apply { verify(networkMapStorage).saveNewActiveNetworkMap(capture())
verify(networkMapStorage).saveNetworkMap(capture()) val capturedNetworkMap = firstValue.networkMap
val capturedNetworkMap = firstValue.verifiedNetworkMapCert(rootCaCert) assertEquals(latestNetParams.serialize().hash, capturedNetworkMap.networkParameterHash)
assertEquals(latestNetworkParameters.serialize().hash, capturedNetworkMap.networkParameterHash) assertThat(capturedNetworkMap.nodeInfoHashes).isEqualTo(nodeInfoHashes)
assertEquals(signedNodeInfoHashes.size, capturedNetworkMap.nodeInfoHashes.size)
assertThat(capturedNetworkMap.nodeInfoHashes).containsAll(signedNodeInfoHashes)
} }
} }
@Test @Test
fun `signNetworkMap does NOT create a new network map if there are no changes`() { fun `signNetworkMap does NOT create a new network map if there are no changes`() {
// given // given
val networkParameters = testNetworkParameters(emptyList()) val netParamsEntity = createNetworkParametersEntity(signingCertAndKeyPair)
val networkMapParametersHash = networkParameters.serialize().bytes.sha256() val netMapEntity = createNetworkMapEntity(signingCertAndKeyPair, netParamsEntity, emptyList())
val networkMap = NetworkMap(emptyList(), networkMapParametersHash, null) whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(netParamsEntity)
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(signedNetworkMap)
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(emptyList()) whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(emptyList())
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters) whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(netMapEntity)
whenever(networkMapStorage.getNetworkParametersOfNetworkMap()).thenReturn(networkParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate))
// when // when
networkMapSigner.signNetworkMap() networkMapSigner.signNetworkMap()
// then // then
// Verify networkMapStorage is not called // Verify networkMapStorage is not called
verify(networkMapStorage, never()).saveNetworkMap(any()) verify(networkMapStorage, never()).saveNewActiveNetworkMap(any())
} }
@Test @Test
fun `signNetworkMap creates a new network map if there is no current network map`() { fun `signNetworkMap creates a new network map if there is no current network map`() {
// given // given
val networkParameters = testNetworkParameters(emptyList()) val netParams = testNetworkParameters()
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(null) whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(createNetworkParametersEntity(signingCertAndKeyPair, netParams))
whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(emptyList()) whenever(networkMapStorage.getActiveNodeInfoHashes()).thenReturn(emptyList())
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters) whenever(networkMapStorage.getActiveNetworkMap()).thenReturn(null)
whenever(signer.signBytes(any())).then { whenever(signer.signBytes(any())).then {
DigitalSignatureWithCert(networkMapCa.certificate, Crypto.doSign(networkMapCa.keyPair.private, it.arguments[0] as ByteArray)) DigitalSignatureWithCert(signingCertAndKeyPair.certificate, Crypto.doSign(signingCertAndKeyPair.keyPair.private, it.arguments[0] as ByteArray))
} }
whenever(signer.signObject(networkParameters)).then { whenever(signer.signObject(netParams)).then {
val serialised = networkParameters.serialize() val serialised = netParams.serialize()
SignedNetworkParameters(serialised, signer.signBytes(serialised.bytes)) SignedNetworkParameters(serialised, signer.signBytes(serialised.bytes))
} }
// when // when
@ -129,10 +122,9 @@ class NetworkMapSignerTest : TestBase() {
// Verify networkMapStorage calls // Verify networkMapStorage calls
verify(networkMapStorage).getActiveNodeInfoHashes() verify(networkMapStorage).getActiveNodeInfoHashes()
verify(networkMapStorage).getLatestNetworkParameters() verify(networkMapStorage).getLatestNetworkParameters()
argumentCaptor<SignedNetworkMap>().apply { argumentCaptor<NetworkMapAndSigned>().apply {
verify(networkMapStorage).saveNetworkMap(capture()) verify(networkMapStorage).saveNewActiveNetworkMap(capture())
val networkMap = firstValue.verifiedNetworkMapCert(rootCaCert) assertEquals(netParams.serialize().hash, firstValue.networkMap.networkParameterHash)
assertEquals(networkParameters.serialize().hash, networkMap.networkParameterHash)
} }
} }
} }

View File

@ -10,12 +10,12 @@
package com.r3.corda.networkmanage.doorman.webservice package com.r3.corda.networkmanage.doorman.webservice
import com.nhaarman.mockito_kotlin.any
import com.nhaarman.mockito_kotlin.mock import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.times import com.nhaarman.mockito_kotlin.times
import com.nhaarman.mockito_kotlin.verify import com.nhaarman.mockito_kotlin.verify
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
import com.r3.corda.networkmanage.createNetworkMapEntity
import com.r3.corda.networkmanage.doorman.NetworkManagementWebServer import com.r3.corda.networkmanage.doorman.NetworkManagementWebServer
import com.r3.corda.networkmanage.doorman.NetworkMapConfig import com.r3.corda.networkmanage.doorman.NetworkMapConfig
import net.corda.core.crypto.SecureHash.Companion.randomSHA256 import net.corda.core.crypto.SecureHash.Companion.randomSHA256
@ -23,14 +23,12 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.checkOkResponse import net.corda.core.internal.checkOkResponse
import net.corda.core.internal.openHttpConnection import net.corda.core.internal.openHttpConnection
import net.corda.core.internal.responseAs import net.corda.core.internal.responseAs
import net.corda.core.internal.signWithCert
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.SignedNodeInfo
import net.corda.nodeapi.internal.createDevNetworkMapCa import net.corda.nodeapi.internal.createDevNetworkMapCa
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.network.NetworkMap
import net.corda.nodeapi.internal.network.SignedNetworkMap import net.corda.nodeapi.internal.network.SignedNetworkMap
import net.corda.nodeapi.internal.network.SignedNetworkParameters import net.corda.nodeapi.internal.network.SignedNetworkParameters
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
@ -54,7 +52,7 @@ class NetworkMapWebServiceTest {
val testSerialization = SerializationEnvironmentRule(true) val testSerialization = SerializationEnvironmentRule(true)
private lateinit var rootCaCert: X509Certificate private lateinit var rootCaCert: X509Certificate
private lateinit var networkMapCa: CertificateAndKeyPair private lateinit var signingCertAndKeyPair: CertificateAndKeyPair
private val testNetworkMapConfig = NetworkMapConfig(10.seconds.toMillis(), 10.seconds.toMillis()) private val testNetworkMapConfig = NetworkMapConfig(10.seconds.toMillis(), 10.seconds.toMillis())
@ -62,16 +60,15 @@ class NetworkMapWebServiceTest {
fun init() { fun init() {
val (rootCa) = createDevIntermediateCaCertPath() val (rootCa) = createDevIntermediateCaCertPath()
rootCaCert = rootCa.certificate rootCaCert = rootCa.certificate
networkMapCa = createDevNetworkMapCa(rootCa) signingCertAndKeyPair = createDevNetworkMapCa(rootCa)
} }
@Test @Test
fun `submit nodeInfo`() { fun `submit nodeInfo`() {
val networkMapStorage: NetworkMapStorage = mock { val networkMapStorage: NetworkMapStorage = mock {
val networkParameter = testNetworkParameters(emptyList()).signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate) on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity())
on { getSignedNetworkParameters(any()) }.thenReturn(networkParameter)
on { getCurrentNetworkMap() }.thenReturn(NetworkMap(emptyList(), networkParameter.raw.hash, null).signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate))
} }
// Create node info. // Create node info.
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB")) val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
@ -86,9 +83,7 @@ class NetworkMapWebServiceTest {
@Test @Test
fun `submit old nodeInfo`() { fun `submit old nodeInfo`() {
val networkMapStorage: NetworkMapStorage = mock { val networkMapStorage: NetworkMapStorage = mock {
val networkParameter = testNetworkParameters(emptyList(), minimumPlatformVersion = 2).signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate) on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity(networkParameters = testNetworkParameters(minimumPlatformVersion = 2)))
on { getSignedNetworkParameters(any()) }.thenReturn(networkParameter)
on { getCurrentNetworkMap() }.thenReturn(NetworkMap(emptyList(), networkParameter.raw.hash, null).signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate))
} }
// Create node info. // Create node info.
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1) val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
@ -102,9 +97,9 @@ class NetworkMapWebServiceTest {
} }
@Test @Test
fun `submit nodeInfo when no network parameters`() { fun `submit nodeInfo when no network map`() {
val networkMapStorage: NetworkMapStorage = mock { val networkMapStorage: NetworkMapStorage = mock {
on { getNetworkParametersOfNetworkMap() }.thenReturn(null) on { getActiveNetworkMap() }.thenReturn(null)
} }
// Create node info. // Create node info.
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1) val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
@ -119,18 +114,19 @@ class NetworkMapWebServiceTest {
@Test @Test
fun `get network map`() { fun `get network map`() {
val networkMap = NetworkMap(listOf(randomSHA256(), randomSHA256()), randomSHA256(), null) val networkMapEntity = createNetworkMapEntity(
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate) signingCertAndKeyPair = signingCertAndKeyPair,
nodeInfoHashes = listOf(randomSHA256(), randomSHA256()))
val networkMapStorage: NetworkMapStorage = mock { val networkMapStorage: NetworkMapStorage = mock {
on { getCurrentNetworkMap() }.thenReturn(signedNetworkMap) on { getActiveNetworkMap() }.thenReturn(networkMapEntity)
} }
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, testNetworkMapConfig)).use { NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, testNetworkMapConfig)).use {
it.start() it.start()
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("") val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
verify(networkMapStorage, times(1)).getCurrentNetworkMap() verify(networkMapStorage, times(1)).getActiveNetworkMap()
assertEquals(signedNetworkMapResponse.verifiedNetworkMapCert(rootCaCert), networkMap) assertEquals(signedNetworkMapResponse.verifiedNetworkMapCert(rootCaCert), networkMapEntity.toNetworkMap())
} }
} }
@ -144,10 +140,8 @@ class NetworkMapWebServiceTest {
} }
// Mock network map storage // Mock network map storage
val networkMap = NetworkMap(listOf(nodeInfoHash), randomSHA256(), null)
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
val networkMapStorage: NetworkMapStorage = mock { val networkMapStorage: NetworkMapStorage = mock {
on { getCurrentNetworkMap() }.thenReturn(signedNetworkMap) on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity(nodeInfoHashes = listOf(nodeInfoHash)))
} }
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(nodeInfoStorage, networkMapStorage, testNetworkMapConfig)).use { NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(nodeInfoStorage, networkMapStorage, testNetworkMapConfig)).use {
@ -165,7 +159,7 @@ class NetworkMapWebServiceTest {
@Test @Test
fun `get network parameters`() { fun `get network parameters`() {
val networkParameters = testNetworkParameters(emptyList()) val networkParameters = testNetworkParameters(emptyList())
val signedNetworkParameters = networkParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate) val signedNetworkParameters = signingCertAndKeyPair.sign(networkParameters)
val networkParametersHash = signedNetworkParameters.raw.hash val networkParametersHash = signedNetworkParameters.raw.hash
val networkMapStorage: NetworkMapStorage = mock { val networkMapStorage: NetworkMapStorage = mock {
@ -177,7 +171,7 @@ class NetworkMapWebServiceTest {
val netParamsResponse = it.doGet<SignedNetworkParameters>("network-parameters/$networkParametersHash") val netParamsResponse = it.doGet<SignedNetworkParameters>("network-parameters/$networkParametersHash")
verify(networkMapStorage, times(1)).getSignedNetworkParameters(networkParametersHash) verify(networkMapStorage, times(1)).getSignedNetworkParameters(networkParametersHash)
assertThat(netParamsResponse.verified()).isEqualTo(networkParameters) assertThat(netParamsResponse.verified()).isEqualTo(networkParameters)
assertThat(netParamsResponse.sig.by).isEqualTo(networkMapCa.certificate) assertThat(netParamsResponse.sig.by).isEqualTo(signingCertAndKeyPair.certificate)
assertThatExceptionOfType(IOException::class.java) assertThatExceptionOfType(IOException::class.java)
.isThrownBy { it.doGet<SignedNetworkParameters>("network-parameters/${randomSHA256()}") } .isThrownBy { it.doGet<SignedNetworkParameters>("network-parameters/${randomSHA256()}") }
.withMessageContaining("404") .withMessageContaining("404")
@ -198,4 +192,4 @@ class NetworkMapWebServiceTest {
private inline fun <reified T : Any> NetworkManagementWebServer.doGet(path: String): T { private inline fun <reified T : Any> NetworkManagementWebServer.doGet(path: String): T {
return URL("http://$hostAndPort/network-map/$path").openHttpConnection().responseAs() return URL("http://$hostAndPort/network-map/$path").openHttpConnection().responseAs()
} }
} }

View File

@ -14,10 +14,7 @@ import net.corda.core.CordaOID
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SignatureScheme import net.corda.core.crypto.SignatureScheme
import net.corda.core.crypto.random63BitValue import net.corda.core.crypto.random63BitValue
import net.corda.core.internal.CertRole import net.corda.core.internal.*
import net.corda.core.internal.reader
import net.corda.core.internal.uncheckedCast
import net.corda.core.internal.writer
import net.corda.core.utilities.days import net.corda.core.utilities.days
import net.corda.core.utilities.millis import net.corda.core.utilities.millis
import org.bouncycastle.asn1.* import org.bouncycastle.asn1.*
@ -425,4 +422,6 @@ enum class CertificateType(val keyUsage: KeyUsage, vararg val purposes: KeyPurpo
) )
} }
data class CertificateAndKeyPair(val certificate: X509Certificate, val keyPair: KeyPair) data class CertificateAndKeyPair(val certificate: X509Certificate, val keyPair: KeyPair) {
fun <T : Any> sign(obj: T): SignedDataWithCert<T> = obj.signWithCert(keyPair.private, certificate)
}

View File

@ -12,10 +12,13 @@ package net.corda.nodeapi.internal.network
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.internal.CertRole import net.corda.core.internal.CertRole
import net.corda.core.internal.DigitalSignatureWithCert
import net.corda.core.internal.SignedDataWithCert import net.corda.core.internal.SignedDataWithCert
import net.corda.core.internal.signWithCert
import net.corda.core.node.NetworkParameters import net.corda.core.node.NetworkParameters
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SerializedBytes
import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.crypto.X509Utilities
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import java.time.Instant import java.time.Instant
@ -63,3 +66,10 @@ fun <T : Any> SignedDataWithCert<T>.verifiedNetworkMapCert(rootCert: X509Certifi
X509Utilities.validateCertificateChain(rootCert, sig.by, rootCert) X509Utilities.validateCertificateChain(rootCert, sig.by, rootCert)
return verified() return verified()
} }
class NetworkMapAndSigned private constructor(val networkMap: NetworkMap, val signed: SignedNetworkMap) {
constructor(networkMap: NetworkMap, signer: (SerializedBytes<NetworkMap>) -> DigitalSignatureWithCert) : this(networkMap, networkMap.signWithCert(signer))
constructor(signed: SignedNetworkMap) : this(signed.verified(), signed)
operator fun component1(): NetworkMap = networkMap
operator fun component2(): SignedNetworkMap = signed
}