From 4cd77dca3a2ea3117fe0277992476012113cd502 Mon Sep 17 00:00:00 2001 From: James Brown <33660060+jamesbr3@users.noreply.github.com> Date: Thu, 22 Nov 2018 10:49:18 +0000 Subject: [PATCH] CORDA-2199 NetworkParameters certificate role (#4278) --- .../kotlin/net/corda/core/internal/CertRole.kt | 5 ++++- .../nodeapi/internal/crypto/X509Utilities.kt | 6 ++++++ .../internal/network/NetworkBootstrapper.kt | 4 ++-- .../nodeapi/internal/network/NetworkMap.kt | 18 +++++++++++++++--- .../network/NetworkBootstrapperTest.kt | 2 +- .../node/internal/NetworkParametersReader.kt | 9 ++++----- .../node/services/network/NetworkMapUpdater.kt | 4 ++-- .../services/network/NetworkMapUpdaterTest.kt | 9 +++------ .../network/NetworkParametersReaderTest.kt | 7 ++----- 9 files changed, 39 insertions(+), 25 deletions(-) diff --git a/core/src/main/kotlin/net/corda/core/internal/CertRole.kt b/core/src/main/kotlin/net/corda/core/internal/CertRole.kt index f2946d3c72..4a7d94832a 100644 --- a/core/src/main/kotlin/net/corda/core/internal/CertRole.kt +++ b/core/src/main/kotlin/net/corda/core/internal/CertRole.kt @@ -46,7 +46,10 @@ enum class CertRole(val validParents: NonEmptySet, val isIdentity: Bo LEGAL_IDENTITY(NonEmptySet.of(DOORMAN_CA, NODE_CA), true, true), /** Confidential (limited visibility) identity of a legal entity. */ - CONFIDENTIAL_LEGAL_IDENTITY(NonEmptySet.of(LEGAL_IDENTITY), true, false); + CONFIDENTIAL_LEGAL_IDENTITY(NonEmptySet.of(LEGAL_IDENTITY), true, false), + + /** Signing certificate for Network Parameters. */ + NETWORK_PARAMETERS(NonEmptySet.of(null), false, false); companion object { private val values by lazy(LazyThreadSafetyMode.NONE, CertRole::values) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt index e78e63716f..5fbb9fcb66 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt @@ -467,6 +467,12 @@ enum class CertificateType(val keyUsage: KeyUsage, vararg val purposes: KeyPurpo KeyPurposeId.anyExtendedKeyUsage, isCA = false, role = CertRole.CONFIDENTIAL_LEGAL_IDENTITY + ), + + NETWORK_PARAMETERS( + KeyUsage(KeyUsage.digitalSignature), + isCA = false, + role = CertRole.NETWORK_PARAMETERS ) } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt index a8dea65b33..11f04dc97b 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt @@ -357,7 +357,7 @@ internal constructor(private val initSerEnv: Boolean, when (netParamsFilesGrouped.size) { 0 -> return null - 1 -> return netParamsFilesGrouped.keys.first().deserialize().verifiedNetworkMapCert(DEV_ROOT_CA.certificate) + 1 -> return netParamsFilesGrouped.keys.first().deserialize().verifiedNetworkParametersCert(DEV_ROOT_CA.certificate) } val msg = StringBuilder("Differing sets of network parameters were found. Make sure all the nodes have the same " + @@ -367,7 +367,7 @@ internal constructor(private val initSerEnv: Boolean, netParamsFiles.map { it.parent.fileName }.joinTo(msg, ", ") msg.append(":\n") val netParamsString = try { - bytes.deserialize().verifiedNetworkMapCert(DEV_ROOT_CA.certificate).toString() + bytes.deserialize().verifiedNetworkParametersCert(DEV_ROOT_CA.certificate).toString() } catch (e: Exception) { "Invalid network parameters file: $e" } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkMap.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkMap.kt index ae164aad99..776de34159 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkMap.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkMap.kt @@ -54,9 +54,9 @@ data class ParametersUpdate( val updateDeadline: Instant ) -/** Verify that a Network Map certificate path and its [CertRole] is correct. */ -fun SignedDataWithCert.verifiedNetworkMapCert(rootCert: X509Certificate): T { - require(CertRole.extract(sig.by) == CertRole.NETWORK_MAP) { "Incorrect cert role: ${CertRole.extract(sig.by)}" } +/** Verify that a certificate path and its [CertRole] is correct. */ +fun SignedDataWithCert.verifiedCertWithRole(rootCert: X509Certificate, vararg certRoles: CertRole): T { + require(CertRole.extract(sig.by) in certRoles) { "Incorrect cert role: ${CertRole.extract(sig.by)}" } val path = if (sig.parentCertsChain.isEmpty()) { listOf(sig.by, rootCert) } else { @@ -65,3 +65,15 @@ fun SignedDataWithCert.verifiedNetworkMapCert(rootCert: X509Certifi X509Utilities.validateCertificateChain(rootCert, path) return verified() } + +/** Verify that a Network Map certificate path and its [CertRole] is correct. */ +fun SignedDataWithCert.verifiedNetworkMapCert(rootCert: X509Certificate): T { + return verifiedCertWithRole(rootCert, CertRole.NETWORK_MAP) +} + +/** Verify that a Network Parameters certificate path and its [CertRole] is correct. */ +fun SignedDataWithCert.verifiedNetworkParametersCert(rootCert: X509Certificate): T { + // for backwards compatibility we allow network parameters to be signed with + // the networkmap cert, but going forwards we also accept the specific netparams cert as well + return verifiedCertWithRole(rootCert, CertRole.NETWORK_PARAMETERS, CertRole.NETWORK_MAP) +} \ No newline at end of file diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapperTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapperTest.kt index cd691b53f4..ac5e5b7104 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapperTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapperTest.kt @@ -321,7 +321,7 @@ class NetworkBootstrapperTest { } private val Path.networkParameters: NetworkParameters get() { - return (this / NETWORK_PARAMS_FILE_NAME).readObject().verifiedNetworkMapCert(DEV_ROOT_CA.certificate) + return (this / NETWORK_PARAMS_FILE_NAME).readObject().verifiedNetworkParametersCert(DEV_ROOT_CA.certificate) } private val Path.nodeInfoFile: Path get() { diff --git a/node/src/main/kotlin/net/corda/node/internal/NetworkParametersReader.kt b/node/src/main/kotlin/net/corda/node/internal/NetworkParametersReader.kt index 98d318f40c..5acfb7e237 100644 --- a/node/src/main/kotlin/net/corda/node/internal/NetworkParametersReader.kt +++ b/node/src/main/kotlin/net/corda/node/internal/NetworkParametersReader.kt @@ -6,10 +6,7 @@ import net.corda.core.node.NetworkParameters import net.corda.core.serialization.serialize import net.corda.core.utilities.contextLogger import net.corda.node.services.network.NetworkMapClient -import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME -import net.corda.nodeapi.internal.network.NETWORK_PARAMS_UPDATE_FILE_NAME -import net.corda.nodeapi.internal.network.SignedNetworkParameters -import net.corda.nodeapi.internal.network.verifiedNetworkMapCert +import net.corda.nodeapi.internal.network.* import java.nio.file.Path import java.nio.file.StandardCopyOption import java.security.cert.X509Certificate @@ -93,7 +90,9 @@ class NetworkParametersReader(private val trustRoot: X509Certificate, // By passing in just the SignedNetworkParameters object, this class guarantees that the networkParameters property // could have only been derived from it. class NetworkParametersAndSigned(val signed: SignedNetworkParameters, trustRoot: X509Certificate) { - val networkParameters: NetworkParameters = signed.verifiedNetworkMapCert(trustRoot) + // for backwards compatibility we allow netparams to be signed with the networkmap cert, + // but going forwards we also accept the distinct netparams cert as well + val networkParameters: NetworkParameters = signed.verifiedNetworkParametersCert(trustRoot) operator fun component1() = networkParameters operator fun component2() = signed } diff --git a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt index 66355758c7..0c80be1589 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt @@ -208,7 +208,7 @@ The node will shutdown now.""") return } val newSignedNetParams = networkMapClient.getNetworkParameters(update.newParametersHash) - val newNetParams = newSignedNetParams.verifiedNetworkMapCert(trustRoot) + val newNetParams = newSignedNetParams.verifiedNetworkParametersCert(trustRoot) logger.info("Downloaded new network parameters: $newNetParams from the update: $update") newNetworkParameters = Pair(update, newSignedNetParams) val updateInfo = ParametersUpdateInfo( @@ -233,7 +233,7 @@ The node will shutdown now.""") // Add persisting of newest parameters from update. val (update, signedNewNetParams) = requireNotNull(newNetworkParameters) { "Couldn't find parameters update for the hash: $parametersHash" } // We should check that we sign the right data structure hash. - val newNetParams = signedNewNetParams.verifiedNetworkMapCert(trustRoot) + val newNetParams = signedNewNetParams.verifiedNetworkParametersCert(trustRoot) val newParametersHash = signedNewNetParams.raw.hash if (parametersHash == newParametersHash) { // The latest parameters have priority. diff --git a/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt b/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt index b6451f3217..57c6ce8e57 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt @@ -22,10 +22,7 @@ import net.corda.core.internal.NODE_INFO_DIRECTORY import net.corda.nodeapi.internal.NodeInfoAndSigned import net.corda.nodeapi.internal.SignedNodeInfo import net.corda.nodeapi.internal.crypto.X509Utilities -import net.corda.nodeapi.internal.network.NETWORK_PARAMS_UPDATE_FILE_NAME -import net.corda.nodeapi.internal.network.NodeInfoFilesCopier -import net.corda.nodeapi.internal.network.SignedNetworkParameters -import net.corda.nodeapi.internal.network.verifiedNetworkMapCert +import net.corda.nodeapi.internal.network.* import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.core.* import net.corda.testing.internal.DEV_ROOT_CA @@ -240,7 +237,7 @@ class NetworkMapUpdaterTest { assert(!updateFile.exists()) { "network parameters should not be auto accepted" } updater.acceptNewNetworkParameters(newHash) { it.serialize().sign(ourKeyPair) } val signedNetworkParams = updateFile.readObject() - val paramsFromFile = signedNetworkParams.verifiedNetworkMapCert(DEV_ROOT_CA.certificate) + val paramsFromFile = signedNetworkParams.verifiedNetworkParametersCert(DEV_ROOT_CA.certificate) assertEquals(newParameters, paramsFromFile) assertEquals(newHash, server.latestParametersAccepted(ourKeyPair.public)) } @@ -258,7 +255,7 @@ class NetworkMapUpdaterTest { val newHash = newParameters.serialize().hash val updateFile = baseDir / NETWORK_PARAMS_UPDATE_FILE_NAME val signedNetworkParams = updateFile.readObject() - val paramsFromFile = signedNetworkParams.verifiedNetworkMapCert(DEV_ROOT_CA.certificate) + val paramsFromFile = signedNetworkParams.verifiedNetworkParametersCert(DEV_ROOT_CA.certificate) assertEquals(newParameters, paramsFromFile) assertEquals(newHash, server.latestParametersAccepted(ourKeyPair.public)) } diff --git a/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersReaderTest.kt b/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersReaderTest.kt index 08fa5c3a85..4378ddc314 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersReaderTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersReaderTest.kt @@ -2,10 +2,7 @@ package net.corda.node.services.network import com.google.common.jimfs.Configuration import com.google.common.jimfs.Jimfs -import net.corda.core.internal.createDirectories -import net.corda.core.internal.div -import net.corda.core.internal.exists -import net.corda.core.internal.readObject +import net.corda.core.internal.* import net.corda.core.serialization.deserialize import net.corda.core.utilities.days import net.corda.core.utilities.seconds @@ -64,7 +61,7 @@ class NetworkParametersReaderTest { // Parameters from update should be moved to `network-parameters` file. val parametersFromFile = (baseDirectory / NETWORK_PARAMS_FILE_NAME) .readObject() - .verifiedNetworkMapCert(DEV_ROOT_CA.certificate) + .verifiedNetworkParametersCert(DEV_ROOT_CA.certificate) assertEquals(server.networkParameters, parametersFromFile) }