mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
CORDA-4062: Bump platform version to 9 for safe identity key rotation (#6777)
This commit is contained in:
parent
4193adf6fd
commit
c9056f171b
@ -11,7 +11,7 @@ java8MinUpdateVersion=171
|
||||
# When incrementing platformVersion make sure to update #
|
||||
# net.corda.core.internal.CordaUtilsKt.PLATFORM_VERSION as well. #
|
||||
# ***************************************************************#
|
||||
platformVersion=8
|
||||
platformVersion=9
|
||||
guavaVersion=28.0-jre
|
||||
# Quasar version to use with Java 8:
|
||||
quasarVersion=0.7.13_r3
|
||||
|
@ -28,7 +28,7 @@ import java.util.jar.JarInputStream
|
||||
|
||||
// *Internal* Corda-specific utilities.
|
||||
|
||||
const val PLATFORM_VERSION = 8
|
||||
const val PLATFORM_VERSION = 9
|
||||
|
||||
fun ServicesForResolution.ensureMinimumPlatformVersion(requiredMinPlatformVersion: Int, feature: String) {
|
||||
checkMinimumPlatformVersion(networkParameters.minimumPlatformVersion, requiredMinPlatformVersion, feature)
|
||||
|
@ -16,4 +16,5 @@ object PlatformVersionSwitches {
|
||||
const val LIMIT_KEYS_IN_SIGNATURE_CONSTRAINTS = 5
|
||||
const val BATCH_DOWNLOAD_COUNTERPARTY_BACKCHAIN = 6
|
||||
const val ENABLE_P2P_COMPRESSION = 7
|
||||
const val CERTIFICATE_ROTATION = 9
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package net.corda.node.services.identity
|
||||
|
||||
import net.corda.core.internal.PLATFORM_VERSION
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.coretesting.internal.stubs.CertificateStoreStubs
|
||||
@ -14,6 +15,7 @@ import net.corda.node.services.keys.KeyManagementServiceInternal
|
||||
import net.corda.nodeapi.internal.DEV_CA_KEY_STORE_PASS
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities.NODE_IDENTITY_KEY_ALIAS
|
||||
import net.corda.nodeapi.internal.storeLegalIdentity
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.BOB_NAME
|
||||
import net.corda.testing.core.CHARLIE_NAME
|
||||
@ -21,6 +23,7 @@ import net.corda.testing.node.internal.FINANCE_CORDAPPS
|
||||
import net.corda.testing.node.internal.InternalMockNetwork
|
||||
import net.corda.testing.node.internal.TestStartedNode
|
||||
import net.corda.testing.node.internal.startFlow
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.junit.After
|
||||
import org.junit.Test
|
||||
import java.nio.file.Path
|
||||
@ -78,7 +81,10 @@ class CertificateRotationTest {
|
||||
|
||||
@Test(timeout = 300_000)
|
||||
fun `restart with rotated key for one node`() {
|
||||
mockNet = InternalMockNetwork(cordappsForAllNodes = FINANCE_CORDAPPS)
|
||||
mockNet = InternalMockNetwork(
|
||||
cordappsForAllNodes = FINANCE_CORDAPPS,
|
||||
initialNetworkParameters = testNetworkParameters(minimumPlatformVersion = PLATFORM_VERSION)
|
||||
)
|
||||
val alice = mockNet.createPartyNode(ALICE_NAME)
|
||||
val bob = mockNet.createPartyNode(BOB_NAME)
|
||||
|
||||
@ -111,9 +117,24 @@ class CertificateRotationTest {
|
||||
assertEquals(1300.POUNDS, bob2.services.getCashBalance(GBP))
|
||||
}
|
||||
|
||||
@Test(timeout = 300_000)
|
||||
fun `fail to restart with rotated key and wrong minimum platform version`() {
|
||||
mockNet = InternalMockNetwork(
|
||||
cordappsForAllNodes = FINANCE_CORDAPPS,
|
||||
initialNetworkParameters = testNetworkParameters(minimumPlatformVersion = 8)
|
||||
)
|
||||
val alice = mockNet.createPartyNode(ALICE_NAME)
|
||||
assertThatThrownBy {
|
||||
mockNet.restartNodeWithRotateIdentityKey(alice)
|
||||
}.hasMessageContaining("Failed to change node legal identity key")
|
||||
}
|
||||
|
||||
@Test(timeout = 300_000)
|
||||
fun `backchain resolution with rotated issuer key`() {
|
||||
mockNet = InternalMockNetwork(cordappsForAllNodes = FINANCE_CORDAPPS)
|
||||
mockNet = InternalMockNetwork(
|
||||
cordappsForAllNodes = FINANCE_CORDAPPS,
|
||||
initialNetworkParameters = testNetworkParameters(minimumPlatformVersion = PLATFORM_VERSION)
|
||||
)
|
||||
val alice = mockNet.createPartyNode(ALICE_NAME)
|
||||
val bob = mockNet.createPartyNode(BOB_NAME)
|
||||
|
||||
|
@ -14,6 +14,7 @@ import net.corda.core.context.InvocationContext
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.newSecureRandom
|
||||
import net.corda.core.crypto.toStringShort
|
||||
import net.corda.core.flows.ContractUpgradeFlow
|
||||
import net.corda.core.flows.FinalityFlow
|
||||
import net.corda.core.flows.FlowLogic
|
||||
@ -31,6 +32,7 @@ import net.corda.core.internal.FlowStateMachineHandle
|
||||
import net.corda.core.internal.NODE_INFO_DIRECTORY
|
||||
import net.corda.core.internal.NamedCacheFactory
|
||||
import net.corda.core.internal.NetworkParametersStorage
|
||||
import net.corda.core.internal.PlatformVersionSwitches
|
||||
import net.corda.core.internal.VisibleForTesting
|
||||
import net.corda.core.internal.concurrent.flatMap
|
||||
import net.corda.core.internal.concurrent.map
|
||||
@ -568,7 +570,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
identityService.start(trustRoots, keyStoreHandler.nodeIdentity, netParams.notaries.map { it.identity }, pkToIdCache)
|
||||
|
||||
val nodeInfoAndSigned = database.transaction {
|
||||
updateNodeInfo(publish = true)
|
||||
updateNodeInfo(publish = true, minimumPlatformVersion = netParams.minimumPlatformVersion)
|
||||
}
|
||||
|
||||
val (nodeInfo, signedNodeInfo) = nodeInfoAndSigned
|
||||
@ -693,7 +695,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateNodeInfo(publish: Boolean): NodeInfoAndSigned {
|
||||
private fun updateNodeInfo(publish: Boolean, minimumPlatformVersion: Int = Int.MAX_VALUE): NodeInfoAndSigned {
|
||||
val potentialNodeInfo = NodeInfo(
|
||||
myAddresses(),
|
||||
setOf(keyStoreHandler.nodeIdentity, keyStoreHandler.notaryIdentity).filterNotNull(),
|
||||
@ -709,6 +711,9 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
nodeInfoFromDb
|
||||
} else {
|
||||
log.info("Node-info has changed so submitting update. Old node-info was $nodeInfoFromDb")
|
||||
if (minimumPlatformVersion < PlatformVersionSwitches.CERTIFICATE_ROTATION && nodeInfoFromDb != null) {
|
||||
requireSameNodeIdentity(nodeInfoFromDb, potentialNodeInfo)
|
||||
}
|
||||
val newNodeInfo = potentialNodeInfo.copy(serial = platformClock.millis())
|
||||
networkMapCache.addOrUpdateNode(newNodeInfo)
|
||||
log.info("New node-info: $newNodeInfo")
|
||||
@ -745,6 +750,16 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
}
|
||||
}
|
||||
|
||||
private fun requireSameNodeIdentity(oldNodeInfo: NodeInfo, newNodeInfo: NodeInfo) {
|
||||
val oldIdentity = oldNodeInfo.legalIdentities.first()
|
||||
val newIdentity = newNodeInfo.legalIdentities.first()
|
||||
require(oldIdentity == newIdentity || oldIdentity.name != newIdentity.name) {
|
||||
"Failed to change node legal identity key from ${oldIdentity.owningKey.toStringShort()}"+
|
||||
" to ${newIdentity.owningKey.toStringShort()}," +
|
||||
" as it requires minimumPlatformVersion >= ${PlatformVersionSwitches.CERTIFICATE_ROTATION}."
|
||||
}
|
||||
}
|
||||
|
||||
// Publish node info on startup and start task that sends every day a heartbeat - republishes node info.
|
||||
private fun tryPublishNodeInfoAsync(signedNodeInfo: SignedNodeInfo, networkMapClient: NetworkMapClient) {
|
||||
// By default heartbeat interval should be set to 1 day, but for testing we may change it.
|
||||
|
@ -262,7 +262,7 @@ class FlowMetadataRecordingTest {
|
||||
it.initialParameters.deserialize(context = SerializationDefaults.STORAGE_CONTEXT)
|
||||
)
|
||||
assertThat(it.launchingCordapp).contains("custom-cordapp")
|
||||
assertEquals(8, it.platformVersion)
|
||||
assertEquals(PLATFORM_VERSION, it.platformVersion)
|
||||
assertEquals(nodeAHandle.nodeInfo.singleIdentity().name.toString(), it.startedBy)
|
||||
assertEquals(context!!.trace.invocationId.timestamp.truncatedTo(ChronoUnit.MILLIS),
|
||||
it.invocationInstant.truncatedTo(ChronoUnit.MILLIS))
|
||||
|
Loading…
Reference in New Issue
Block a user