HSM signing of network parameters (#363)

Add HSM signing of network parameters
This commit is contained in:
Katarzyna Streich 2018-01-18 12:05:18 +00:00 committed by GitHub
parent af21f6065d
commit f2f803ecd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 144 additions and 92 deletions

View File

@ -3,6 +3,7 @@ package com.r3.corda.networkmanage.common.persistence
import com.r3.corda.networkmanage.common.utils.SignedNetworkMap
import com.r3.corda.networkmanage.common.utils.SignedNetworkParameters
import net.corda.core.crypto.SecureHash
import net.corda.core.internal.DigitalSignatureWithCert
import net.corda.nodeapi.internal.network.NetworkParameters
/**
@ -31,26 +32,28 @@ interface NetworkMapStorage {
fun saveNetworkMap(signedNetworkMap: SignedNetworkMap)
/**
* Return the signed network parameters object which matches the given hash. The hash is that of the underlying
* [NetworkParameters] object and not the `SignedData<NetworkParameters>` object that's returned.
* 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.
* @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?
/**
* Retrieve network map parameters.
* @return current network map parameters or null if they don't exist
* @return signed current network map parameters or null if they don't exist
*/
fun getCurrentNetworkParameters(): NetworkParameters?
fun getCurrentSignedNetworkParameters(): SignedNetworkParameters?
/**
* Persists given network parameters.
* @return hash corresponding to newly create network parameters entry
* Persists given network parameters with signature if provided.
* @return hash corresponding to newly created network parameters entry
*/
fun saveNetworkParameters(networkParameters: NetworkParameters): SecureHash
fun saveNetworkParameters(networkParameters: NetworkParameters, sig: DigitalSignatureWithCert?): SecureHash
/**
* Retrieves the latest (i.e. most recently inserted) network parameters
* Note that they may not have been signed up yet.
* @return latest network parameters
*/
fun getLatestNetworkParameters(): NetworkParameters
fun getLatestUnsignedNetworkParameters(): NetworkParameters
}

View File

@ -3,9 +3,9 @@ package com.r3.corda.networkmanage.common.persistence
import com.r3.corda.networkmanage.common.persistence.entity.*
import com.r3.corda.networkmanage.common.utils.SignedNetworkMap
import com.r3.corda.networkmanage.common.utils.SignedNetworkParameters
import com.r3.corda.networkmanage.doorman.signer.LocalSigner
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.sha256
import net.corda.core.internal.DigitalSignatureWithCert
import net.corda.core.serialization.SerializedBytes
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
@ -16,7 +16,7 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence
/**
* Database implementation of the [NetworkMapStorage] interface
*/
class PersistentNetworkMapStorage(private val database: CordaPersistence, private val localSigner: LocalSigner?) : NetworkMapStorage {
class PersistentNetworkMapStorage(private val database: CordaPersistence) : NetworkMapStorage {
override fun getCurrentNetworkMap(): SignedNetworkMap? {
return database.transaction {
getCurrentNetworkMapEntity()?.let {
@ -26,11 +26,11 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence, privat
}
}
override fun getCurrentNetworkParameters(): NetworkParameters? {
override fun getCurrentSignedNetworkParameters(): SignedNetworkParameters? {
return database.transaction {
getCurrentNetworkMapEntity()?.let {
val netParamsHash = it.networkMap.deserialize<NetworkMap>().networkParameterHash
getNetworkParametersEntity(netParamsHash.toString())?.networkParameters()
getSignedNetworkParameters(netParamsHash)
}
}
}
@ -46,12 +46,8 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence, privat
}
}
// TODO The signing cannot occur here as it won't work with an HSM. The signed network parameters needs to be persisted
// into the database.
override fun getSignedNetworkParameters(hash: SecureHash): SignedNetworkParameters? {
val netParamsBytes = getNetworkParametersEntity(hash.toString())?.parametersBytes ?: return null
val sigWithCert = localSigner!!.signBytes(netParamsBytes)
return SignedNetworkParameters(SerializedBytes(netParamsBytes), sigWithCert)
return getNetworkParametersEntity(hash.toString())?.signedParameters()
}
override fun getNodeInfoHashes(certificateStatus: CertificateStatus): List<SecureHash> {
@ -69,31 +65,32 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence, privat
}
}
override fun saveNetworkParameters(networkParameters: NetworkParameters): SecureHash {
override fun saveNetworkParameters(networkParameters: NetworkParameters, sig: DigitalSignatureWithCert?): SecureHash {
return database.transaction {
val bytes = networkParameters.serialize().bytes
val hash = bytes.sha256()
session.save(NetworkParametersEntity(
session.saveOrUpdate(NetworkParametersEntity(
parametersBytes = bytes,
parametersHash = hash.toString()
parametersHash = hash.toString(),
signature = sig?.bytes,
certificate = sig?.by?.encoded
))
hash
}
}
override fun getLatestNetworkParameters(): NetworkParameters = getLatestNetworkParametersEntity().networkParameters()
override fun getLatestUnsignedNetworkParameters(): NetworkParameters = getLatestNetworkParametersEntity().networkParameters()
private fun getLatestNetworkParametersEntity(): NetworkParametersEntity {
return database.transaction {
val builder = session.criteriaBuilder
val query = builder.createQuery(NetworkParametersEntity::class.java).run {
// TODO a limit of 1 since we only need the first result
from(NetworkParametersEntity::class.java).run {
orderBy(builder.desc(get<String>(NetworkParametersEntity::version.name)))
orderBy(builder.desc(get<String>(NetworkParametersEntity::created.name)))
}
}
// We just want the last signed entry
session.createQuery(query).resultList.first()
// We just want the last entry
session.createQuery(query).setMaxResults(1).resultList.singleOrNull() ?: throw IllegalArgumentException("No network parameters found in network map storage")
}
}

View File

@ -1,22 +1,47 @@
package com.r3.corda.networkmanage.common.persistence.entity
import com.r3.corda.networkmanage.common.utils.SignedNetworkParameters
import net.corda.core.internal.DigitalSignatureWithCert
import net.corda.core.internal.SignedDataWithCert
import net.corda.core.serialization.SerializedBytes
import net.corda.core.serialization.deserialize
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
import net.corda.nodeapi.internal.network.NetworkParameters
import org.hibernate.annotations.CreationTimestamp
import java.time.Instant
import javax.persistence.*
@Entity
@Table(name = "network_parameters")
@Table(name = "network_parameters", indexes = arrayOf(Index(name = "IDX_NET_PARAMS_HASH", columnList = "hash")))
class NetworkParametersEntity(
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
val version: Long? = null,
@Column(name = "hash", length = 64, unique = true)
val parametersHash: String,
@CreationTimestamp
val created: Instant = Instant.now(),
@Lob
@Column(name = "bytes")
val parametersBytes: ByteArray
@Column(name = "parameters_bytes")
val parametersBytes: ByteArray,
// Both of the fields below are nullable, because of the way we sign network map data. NetworkParameters can be
// inserted into database without signature. Then signing service will sign them.
@Lob
@Column(name = "signature")
val signature: ByteArray?,
@Lob
@Column(name = "certificate")
val certificate: ByteArray?
) {
fun networkParameters(): NetworkParameters = parametersBytes.deserialize()
// Return signed network parameters or null if they haven't been signed yet.
fun signedParameters(): SignedNetworkParameters? {
return if (certificate != null && signature != null) {
val sigWithCert = DigitalSignatureWithCert(X509CertificateFactory().generateCertificate(certificate.inputStream()), signature)
SignedDataWithCert(SerializedBytes(parametersBytes), sigWithCert)
} else null
}
}

View File

@ -5,19 +5,33 @@ import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
import net.corda.core.internal.SignedDataWithCert
import net.corda.core.serialization.serialize
import net.corda.nodeapi.internal.network.NetworkMap
import net.corda.nodeapi.internal.network.NetworkParameters
class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private val signer: Signer) {
/**
* Signs the network map.
* Signs the network map and latest network parameters if they haven't been signed yet.
*/
fun signNetworkMap() {
// TODO There is no network parameters update process in place yet. We assume that latest parameters are to be used
// in current network map.
val latestNetworkParameters = networkMapStorage.getLatestUnsignedNetworkParameters()
val currentNetworkParameters = networkMapStorage.getCurrentSignedNetworkParameters()
if (currentNetworkParameters?.verified() != latestNetworkParameters)
signNetworkParameters(latestNetworkParameters)
val currentSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
val nodeInfoHashes = networkMapStorage.getNodeInfoHashes(CertificateStatus.VALID)
val networkParameters = networkMapStorage.getLatestNetworkParameters()
val serialisedNetworkMap = NetworkMap(nodeInfoHashes, networkParameters.serialize().hash).serialize()
val serialisedNetworkMap = NetworkMap(nodeInfoHashes, latestNetworkParameters.serialize().hash).serialize()
if (serialisedNetworkMap != currentSignedNetworkMap?.raw) {
val newSignedNetworkMap = SignedDataWithCert(serialisedNetworkMap, signer.signBytes(serialisedNetworkMap.bytes))
networkMapStorage.saveNetworkMap(newSignedNetworkMap)
}
}
/**
* Signs latest inserted network parameters.
*/
fun signNetworkParameters(networkParameters: NetworkParameters) {
val digitalSignature = signer.signObject(networkParameters).sig
networkMapStorage.saveNetworkParameters(networkParameters, digitalSignature)
}
}

View File

@ -9,7 +9,7 @@ import net.corda.core.serialization.serialize
*/
interface Signer {
/**
* Signs given bytes. The signing key selction strategy is left to the implementing class.
* Signs given bytes. The signing key selection strategy is left to the implementing class.
* @return [DigitalSignatureWithCert] that encapsulates the signature and the certificate path used in the signing process.
* @throws [AuthenticationException] if fails authentication
*/

View File

@ -52,14 +52,15 @@ class NetworkManagementServer : Closeable {
}
private fun getNetworkMapService(config: NetworkMapConfig, database: CordaPersistence, signer: LocalSigner?, updateNetworkParameters: NetworkParameters?): NodeInfoWebService {
val networkMapStorage = PersistentNetworkMapStorage(database, signer)
val networkMapStorage = PersistentNetworkMapStorage(database)
val nodeInfoStorage = PersistentNodeInfoStorage(database)
val localNetworkMapSigner = if (signer != null) NetworkMapSigner(networkMapStorage, signer) else null
updateNetworkParameters?.let {
// Persisting new network parameters
val currentNetworkParameters = networkMapStorage.getCurrentNetworkParameters()
val currentNetworkParameters = networkMapStorage.getCurrentSignedNetworkParameters()
if (currentNetworkParameters == null) {
networkMapStorage.saveNetworkParameters(it)
localNetworkMapSigner?.signNetworkParameters(it) ?: networkMapStorage.saveNetworkParameters(it, null)
} else {
throw UnsupportedOperationException("Network parameters already exist. Updating them via the file config is not supported yet.")
}
@ -67,21 +68,19 @@ class NetworkManagementServer : Closeable {
// This call will fail if parameter is null in DB.
try {
val latestParameter = networkMapStorage.getLatestNetworkParameters()
val latestParameter = networkMapStorage.getLatestUnsignedNetworkParameters()
logger.info("Starting network map service with network parameters : $latestParameter")
} catch (e: NoSuchElementException) {
logger.error("No network parameter found, please upload new network parameter before starting network map service. The server will now exit.")
exitProcess(-1)
}
val networkMapSigner = if (signer != null) NetworkMapSigner(networkMapStorage, signer) else null
// Thread sign network map in case of change (i.e. a new node info has been added or a node info has been removed).
if (networkMapSigner != null) {
if (localNetworkMapSigner != null) {
val scheduledExecutor = Executors.newScheduledThreadPool(1)
val signingThread = Runnable {
try {
networkMapSigner.signNetworkMap()
localNetworkMapSigner.signNetworkMap()
} catch (e: Exception) {
// Log the error and carry on.
logger.error("Error encountered when processing node info changes.", e)
@ -141,7 +140,6 @@ class NetworkManagementServer : Closeable {
val services = mutableListOf<Any>()
val serverStatus = NetworkManagementServerStatus()
// TODO: move signing to signing server.
startNetworkMap?.let { services += getNetworkMapService(it.config, database, it.signer, it.updateNetworkParameters) }
doormanServiceParameter?.let { services += getDoormanService(it, database, doormanSigner, serverStatus) }

View File

@ -7,6 +7,7 @@ import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
import com.r3.corda.networkmanage.common.persistence.NodeInfoWithSigned
import com.r3.corda.networkmanage.common.utils.SignedNetworkMap
import com.r3.corda.networkmanage.common.utils.SignedNetworkParameters
import com.r3.corda.networkmanage.doorman.NetworkMapConfig
import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService.Companion.NETWORK_MAP_PATH
import net.corda.core.crypto.SecureHash
@ -41,7 +42,7 @@ class NodeInfoWebService(private val nodeInfoStorage: NodeInfoStorage,
private val networkMapCache: LoadingCache<Boolean, Pair<SignedNetworkMap?, NetworkParameters?>> = CacheBuilder.newBuilder()
.expireAfterWrite(config.cacheTimeout, TimeUnit.MILLISECONDS)
.build(CacheLoader.from { _ -> Pair(networkMapStorage.getCurrentNetworkMap(), networkMapStorage.getCurrentNetworkParameters()) })
.build(CacheLoader.from { _ -> Pair(networkMapStorage.getCurrentNetworkMap(), networkMapStorage.getCurrentSignedNetworkParameters()?.verified()) })
@POST
@Path("publish")

View File

@ -46,8 +46,7 @@ fun run(parameters: Parameters) {
checkNotNull(dataSourceProperties)
val database = configureDatabase(dataSourceProperties, databaseConfig)
val csrStorage = DBSignedCertificateRequestStorage(database)
// TODO Remove the dependency for a local signer to make signing of network parameters work with an HSM
val networkMapStorage = PersistentNetworkMapStorage(database, localSigner = null)
val networkMapStorage = PersistentNetworkMapStorage(database)
val hsmNetworkMapSigningThread = HsmNetworkMapSigner(
networkMapStorage,
networkMapCertificateName,

View File

@ -93,11 +93,13 @@
</changeSet>
<changeSet author="R3.Corda" id="1513267683777-8">
<createTable tableName="network_parameters">
<column name="version" type="BIGINT">
<column name="hash" type="NVARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="bytes" type="BLOB"/>
<column name="hash" type="NVARCHAR(64)"/>
<column name="certificate" type="BLOB"/>
<column name="created" type="TIMESTAMP"/>
<column name="parameters_bytes" type="BLOB"/>
<column name="signature" type="BLOB"/>
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1513267683777-9">
@ -120,7 +122,7 @@
</createTable>
</changeSet>
<changeSet author="R3.Corda" id="1513267683777-11">
<addPrimaryKey columnNames="version" constraintName="CONSTRAINT_3" tableName="network_parameters"/>
<addPrimaryKey columnNames="hash" constraintName="CONSTRAINT_3" tableName="network_parameters"/>
</changeSet>
<changeSet author="R3.Corda" id="1513267683777-12">
<addPrimaryKey columnNames="id" constraintName="CONSTRAINT_7" tableName="certificate_data"/>
@ -167,6 +169,11 @@
<column name="public_key_hash"/>
</createIndex>
</changeSet>
<changeSet author="R3.Corda" id="network-parameters-idx">
<createIndex indexName="IDX_NET_PARAMS_HASH" tableName="network_parameters">
<column name="hash"/>
</createIndex>
</changeSet>
<changeSet author="R3.Corda" id="1513267683777-24">
<addForeignKeyConstraint baseColumnNames="rev" baseTableName="certificate_signing_request_AUD"
constraintName="FK5g5cagcrx7siu8lwtavirunxd"

View File

@ -1,7 +1,6 @@
package com.r3.corda.networkmanage.common.persistence
import com.r3.corda.networkmanage.TestBase
import com.r3.corda.networkmanage.doorman.signer.LocalSigner
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.signWithCert
import net.corda.nodeapi.internal.createDevNetworkMapCa
@ -37,7 +36,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
rootCaCert = rootCa.certificate
networkMapCa = createDevNetworkMapCa(rootCa)
persistence = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true))
networkMapStorage = PersistentNetworkMapStorage(persistence, LocalSigner(networkMapCa.keyPair, arrayOf(networkMapCa.certificate, rootCaCert)))
networkMapStorage = PersistentNetworkMapStorage(persistence)
nodeInfoStorage = PersistentNodeInfoStorage(persistence)
requestStorage = PersistentCertificateRequestStorage(persistence)
}
@ -48,15 +47,16 @@ class PersistentNetworkMapStorageTest : TestBase() {
}
@Test
fun `signNetworkMap creates current network map`() {
fun `saveNetworkMap and saveNetworkParameters create current network map and parameters`() {
// given
// Create node info.
val signedNodeInfo = createValidSignedNodeInfo("Test")
val nodeInfoHash = nodeInfoStorage.putNodeInfo(signedNodeInfo)
val networkParameters = testNetworkParameters(emptyList())
val parametersSignature = networkParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate).sig
// Create network parameters
val networkParametersHash = networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList()))
val networkParametersHash = networkMapStorage.saveNetworkParameters(networkParameters, parametersSignature)
val networkMap = NetworkMap(listOf(nodeInfoHash), networkParametersHash)
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
@ -65,20 +65,26 @@ class PersistentNetworkMapStorageTest : TestBase() {
// then
val persistedSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
val persistedSignedParameters = networkMapStorage.getCurrentSignedNetworkParameters()
assertEquals(networkParameters, persistedSignedParameters?.verifiedNetworkMapCert(rootCaCert))
assertEquals(parametersSignature, persistedSignedParameters?.sig)
assertEquals(signedNetworkMap.sig, persistedSignedNetworkMap?.sig)
assertEquals(signedNetworkMap.verifiedNetworkMapCert(rootCaCert), persistedSignedNetworkMap?.verifiedNetworkMapCert(rootCaCert))
assertEquals(signedNetworkMap.verifiedNetworkMapCert(rootCaCert).networkParameterHash, persistedSignedParameters?.raw?.hash)
}
@Test
fun `getLatestNetworkParameters returns last inserted`() {
val params1 = testNetworkParameters(emptyList(), minimumPlatformVersion = 1)
val params2 = testNetworkParameters(emptyList(), minimumPlatformVersion = 2)
// given
networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList(), minimumPlatformVersion = 1))
networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList(), minimumPlatformVersion = 2))
networkMapStorage.saveNetworkParameters(params1, params1.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate).sig)
// We may have not signed them yet.
networkMapStorage.saveNetworkParameters(params2, null)
// when
val latest = networkMapStorage.getLatestNetworkParameters()
val latest = networkMapStorage.getLatestUnsignedNetworkParameters()
// then
assertEquals(2, latest.minimumPlatformVersion)
}
@ -87,7 +93,8 @@ class PersistentNetworkMapStorageTest : TestBase() {
fun `getCurrentNetworkParameters returns current network map parameters`() {
// given
// Create network parameters
val networkParametersHash = networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList()))
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
@ -96,25 +103,16 @@ class PersistentNetworkMapStorageTest : TestBase() {
networkMapStorage.saveNetworkMap(signedNetworkMap)
// Create new network parameters
networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList(), minimumPlatformVersion = 2))
val testParameters2 = testNetworkParameters(emptyList(), minimumPlatformVersion = 2)
networkMapStorage.saveNetworkParameters(testParameters2, testParameters2.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate).sig)
// when
val result = networkMapStorage.getCurrentNetworkParameters()
val result = networkMapStorage.getCurrentSignedNetworkParameters()?.verifiedNetworkMapCert(rootCaCert)
// then
assertEquals(1, result?.minimumPlatformVersion)
}
// This test will probably won't be needed when we remove the explicit use of LocalSigner
@Test
fun `getSignedNetworkParameters uses the local signer to return a signed object`() {
val networkParameters = testNetworkParameters(emptyList())
val netParamsHash = networkMapStorage.saveNetworkParameters(networkParameters)
val signedNetworkParameters = networkMapStorage.getSignedNetworkParameters(netParamsHash)
assertThat(signedNetworkParameters?.verifiedNetworkMapCert(rootCaCert)).isEqualTo(networkParameters)
assertThat(signedNetworkParameters?.sig?.by).isEqualTo(networkMapCa.certificate)
}
@Test
fun `getValidNodeInfoHashes returns only valid and signed node info hashes`() {
// given
@ -127,7 +125,8 @@ class PersistentNetworkMapStorageTest : TestBase() {
val nodeInfoHashB = nodeInfoStorage.putNodeInfo(signedNodeInfoB)
// Create network parameters
val networkParametersHash = networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList()))
val testParameters = testNetworkParameters(emptyList())
val networkParametersHash = networkMapStorage.saveNetworkParameters(testParameters, testParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate).sig)
val networkMap = NetworkMap(listOf(nodeInfoHashA), networkParametersHash)
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)

View File

@ -6,9 +6,7 @@ import com.r3.corda.networkmanage.common.utils.hashString
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.identity.CordaX500Name
import net.corda.core.node.NodeInfo
import net.corda.core.serialization.serialize
import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
@ -33,7 +31,6 @@ class PersistentNodeInfoStorageTest : TestBase() {
private lateinit var requestStorage: CertificationRequestStorage
private lateinit var nodeInfoStorage: PersistentNodeInfoStorage
private lateinit var persistence: CordaPersistence
private lateinit var rootCaCert: X509Certificate
private lateinit var intermediateCa: CertificateAndKeyPair

View File

@ -8,6 +8,7 @@ import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.sha256
import net.corda.core.internal.DigitalSignatureWithCert
import net.corda.core.internal.SignedDataWithCert
import net.corda.core.internal.signWithCert
import net.corda.core.serialization.serialize
import net.corda.nodeapi.internal.createDevNetworkMapCa
@ -16,10 +17,10 @@ import net.corda.nodeapi.internal.network.NetworkMap
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.internal.createDevIntermediateCaCertPath
import java.security.cert.X509Certificate
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Test
import java.security.cert.X509Certificate
import kotlin.test.assertEquals
class NetworkMapSignerTest : TestBase() {
@ -41,18 +42,24 @@ class NetworkMapSignerTest : TestBase() {
}
@Test
fun `signNetworkMap builds and signs network map`() {
fun `signNetworkMap builds and signs network map and network parameters`() {
// given
val signedNodeInfoHashes = listOf(SecureHash.randomSHA256(), SecureHash.randomSHA256())
val networkParameters = testNetworkParameters(emptyList())
val networkMap = NetworkMap(signedNodeInfoHashes, SecureHash.randomSHA256())
val currentParameters = testNetworkParameters(emptyList(), minimumPlatformVersion = 1)
val latestNetworkParameters = testNetworkParameters(emptyList(), minimumPlatformVersion = 2)
val networkMap = NetworkMap(signedNodeInfoHashes, currentParameters.serialize().hash)
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(signedNetworkMap)
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(signedNodeInfoHashes)
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
whenever(networkMapStorage.getLatestUnsignedNetworkParameters()).thenReturn(latestNetworkParameters)
whenever(networkMapStorage.getCurrentSignedNetworkParameters()).thenReturn(currentParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate))
whenever(signer.signBytes(any())).then {
DigitalSignatureWithCert(networkMapCa.certificate, Crypto.doSign(networkMapCa.keyPair.private, it.arguments[0] as ByteArray))
}
whenever(signer.signObject(latestNetworkParameters)).then {
val serialised = latestNetworkParameters.serialize()
SignedDataWithCert(serialised, signer.signBytes(serialised.bytes))
}
// when
networkMapSigner.signNetworkMap()
@ -60,11 +67,12 @@ class NetworkMapSignerTest : TestBase() {
// then
// Verify networkMapStorage calls
verify(networkMapStorage).getNodeInfoHashes(any())
verify(networkMapStorage).getLatestNetworkParameters()
verify(networkMapStorage).getLatestUnsignedNetworkParameters()
verify(networkMapStorage).getCurrentSignedNetworkParameters()
argumentCaptor<SignedNetworkMap>().apply {
verify(networkMapStorage).saveNetworkMap(capture())
val capturedNetworkMap = firstValue.verifiedNetworkMapCert(rootCaCert)
assertEquals(networkParameters.serialize().hash, capturedNetworkMap.networkParameterHash)
assertEquals(latestNetworkParameters.serialize().hash, capturedNetworkMap.networkParameterHash)
assertEquals(signedNodeInfoHashes.size, capturedNetworkMap.nodeInfoHashes.size)
assertThat(capturedNetworkMap.nodeInfoHashes).containsAll(signedNodeInfoHashes)
}
@ -79,7 +87,8 @@ class NetworkMapSignerTest : TestBase() {
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(signedNetworkMap)
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList())
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
whenever(networkMapStorage.getLatestUnsignedNetworkParameters()).thenReturn(networkParameters)
whenever(networkMapStorage.getCurrentSignedNetworkParameters()).thenReturn(networkParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate))
// when
networkMapSigner.signNetworkMap()
@ -95,17 +104,21 @@ class NetworkMapSignerTest : TestBase() {
val networkParameters = testNetworkParameters(emptyList())
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(null)
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList())
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
whenever(networkMapStorage.getLatestUnsignedNetworkParameters()).thenReturn(networkParameters)
whenever(signer.signBytes(any())).then {
DigitalSignatureWithCert(networkMapCa.certificate, Crypto.doSign(networkMapCa.keyPair.private, it.arguments[0] as ByteArray))
}
whenever(signer.signObject(networkParameters)).then {
val serialised = networkParameters.serialize()
SignedDataWithCert(serialised, signer.signBytes(serialised.bytes))
}
// when
networkMapSigner.signNetworkMap()
// then
// Verify networkMapStorage calls
verify(networkMapStorage).getNodeInfoHashes(any())
verify(networkMapStorage).getLatestNetworkParameters()
verify(networkMapStorage).getLatestUnsignedNetworkParameters()
argumentCaptor<SignedNetworkMap>().apply {
verify(networkMapStorage).saveNetworkMap(capture())
val networkMap = firstValue.verifiedNetworkMapCert(rootCaCert)

View File

@ -56,7 +56,7 @@ class NodeInfoWebServiceTest {
@Test
fun `submit nodeInfo`() {
val networkMapStorage: NetworkMapStorage = mock {
on { getCurrentNetworkParameters() }.thenReturn(testNetworkParameters(emptyList()))
on { getCurrentSignedNetworkParameters() }.thenReturn(testNetworkParameters(emptyList()).signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate))
}
// Create node info.
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
@ -72,7 +72,7 @@ class NodeInfoWebServiceTest {
@Test
fun `submit old nodeInfo`() {
val networkMapStorage: NetworkMapStorage = mock {
on { getCurrentNetworkParameters() }.thenReturn(testNetworkParameters(emptyList(), minimumPlatformVersion = 2))
on { getCurrentSignedNetworkParameters() }.thenReturn(testNetworkParameters(emptyList(), minimumPlatformVersion = 2).signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate))
}
// Create node info.
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
@ -88,7 +88,7 @@ class NodeInfoWebServiceTest {
@Test
fun `submit nodeInfo when no network parameters`() {
val networkMapStorage: NetworkMapStorage = mock {
on { getCurrentNetworkParameters() }.thenReturn(null)
on { getCurrentSignedNetworkParameters() }.thenReturn(null)
}
// Create node info.
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
@ -155,7 +155,6 @@ class NodeInfoWebServiceTest {
verify(networkMapStorage, times(1)).getSignedNetworkParameters(networkParametersHash)
assertThat(netParamsResponse.verified()).isEqualTo(networkParameters)
assertThat(netParamsResponse.sig.by).isEqualTo(networkMapCa.certificate)
assertThatExceptionOfType(IOException::class.java)
.isThrownBy { it.doGet<SignedNetworkParameters>("network-parameters/${randomSHA256()}") }
.withMessageContaining("404")

View File

@ -41,9 +41,9 @@ import javax.ws.rs.core.MediaType
import kotlin.test.assertEquals
class RegistrationWebServiceTest : TestBase() {
private lateinit var webServer: NetworkManagementWebServer
private lateinit var rootCaCert: X509Certificate
private lateinit var intermediateCa: CertificateAndKeyPair
private lateinit var webServer: NetworkManagementWebServer
@Before
fun init() {