mirror of
https://github.com/corda/corda.git
synced 2025-03-28 22:59:09 +00:00
Updating network-management to use DigitalSignatureWithCert, network map certs and other relevant changes from O/S.
This commit is contained in:
parent
c71ef3139b
commit
b1509607cb
@ -134,8 +134,8 @@ networkMapConfig {
|
||||
|
||||
### 1. Create keystore for local signer
|
||||
|
||||
If local signer is enabled, the server will look for keystores in the certificate folder on start up.
|
||||
The keystores can be created using `--mode` flag.
|
||||
If local signer is enabled, the server will look for key stores in the certificate folder on start up.
|
||||
The key stores can be created using `--mode` flag.
|
||||
```
|
||||
java -jar doorman-<version>.jar --mode ROOT_KEYGEN
|
||||
```
|
||||
@ -180,8 +180,8 @@ networkMapConfig {
|
||||
Save the parameters to `network-parameters.conf`
|
||||
|
||||
### 5. Load initial network parameters file for network map service
|
||||
A network parameters file is required to start the network map service for the first time. The initial network parameters file can be loaded using the `--update-network-parameter` flag.
|
||||
A network parameters file is required to start the network map service for the first time. The initial network parameters file can be loaded using the `--update-network-parameters` flag.
|
||||
We can now restart the network management server with both doorman and network map service.
|
||||
```
|
||||
java -jar doorman-<version>.jar --update-network-parameter network-parameters.conf
|
||||
java -jar doorman-<version>.jar --update-network-parameters network-parameters.conf
|
||||
```
|
||||
|
@ -15,6 +15,7 @@ import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.core.utilities.seconds
|
||||
import net.corda.finance.DOLLARS
|
||||
import net.corda.finance.flows.CashIssueAndPaymentFlow
|
||||
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||
@ -60,15 +61,17 @@ class NodeRegistrationTest : IntegrationTest() {
|
||||
private val dbId = random63BitValue().toString()
|
||||
|
||||
private lateinit var rootCaCert: X509Certificate
|
||||
private lateinit var intermediateCa: CertificateAndKeyPair
|
||||
private lateinit var csrCa: CertificateAndKeyPair
|
||||
private lateinit var networkMapCa: CertificateAndKeyPair
|
||||
|
||||
private var server: NetworkManagementServer? = null
|
||||
|
||||
@Before
|
||||
fun init() {
|
||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||
val (rootCa, doormanCa) = createDevIntermediateCaCertPath()
|
||||
rootCaCert = rootCa.certificate
|
||||
this.intermediateCa = intermediateCa
|
||||
this.csrCa = doormanCa
|
||||
networkMapCa = createDevNetworkMapCa(rootCa)
|
||||
}
|
||||
|
||||
@After
|
||||
@ -138,10 +141,15 @@ class NodeRegistrationTest : IntegrationTest() {
|
||||
start(
|
||||
serverAddress,
|
||||
configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true)),
|
||||
LocalSigner(intermediateCa.keyPair, arrayOf(intermediateCa.certificate, rootCaCert)),
|
||||
networkParameters,
|
||||
networkParameters?.let { NetworkMapConfig(cacheTimeout = timeoutMillis, signInterval = timeoutMillis) },
|
||||
DoormanConfig(approveAll = true, jiraConfig = null, approveInterval = timeoutMillis)
|
||||
LocalSigner(csrCa.keyPair, arrayOf(csrCa.certificate, rootCaCert)),
|
||||
DoormanConfig(approveAll = true, jiraConfig = null, approveInterval = timeoutMillis),
|
||||
networkParameters?.let {
|
||||
NetworkMapStartParams(
|
||||
LocalSigner(networkMapCa.keyPair, arrayOf(networkMapCa.certificate, rootCaCert)),
|
||||
networkParameters,
|
||||
NetworkMapConfig(cacheTimeout = timeoutMillis, signInterval = timeoutMillis)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
package com.r3.corda.networkmanage.hsm
|
||||
|
||||
import com.r3.corda.networkmanage.hsm.SigningServiceIntegrationTest.Companion.DB_NAME
|
||||
import com.r3.corda.networkmanage.hsm.SigningServiceIntegrationTest.Companion.H2_TCP_PORT
|
||||
import com.r3.corda.networkmanage.hsm.SigningServiceIntegrationTest.Companion.HOST
|
||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* The main method for an interactive HSM signing service test/demo. It is supposed to be executed with the
|
||||
* `DEMO - Create CSR and poll` method located in the [SigningServiceIntegrationTest], which is responsible for simulating
|
||||
* CSR creation on the Doorman side.
|
||||
* Execution instructions:
|
||||
* 1) It is assumed that the HSM simulator is installed locally (or via means of the VM) and accessible under the address
|
||||
* configured under the 'device' parameter (defaults to 3001@127.0.0.1). If that is not the case please specify
|
||||
* a correct 'device' parameter value. Also, it is assumed that the HSM setup consists of a cryptographic user eligible to
|
||||
* sign the CSRs (and potentially to generate new root and intermediate certificates).
|
||||
* 2) Run the `DEMO - Create CSR and poll` as a regular test from your IntelliJ.
|
||||
* The method starts the doorman, creates 3 CSRs for ALICE, BOB and CHARLIE
|
||||
* and then polls the doorman until all 3 requests are signed.
|
||||
* 3) Once the `DEMO - Create CSR and poll` is started, execute the following main method
|
||||
* and interact with console menu options presented.
|
||||
*/
|
||||
fun main(args: Array<String>) {
|
||||
run(Parameters(
|
||||
dataSourceProperties = makeTestDataSourceProperties(),
|
||||
databaseConfig = makeNotInitialisingTestDatabaseProperties(),
|
||||
csrPrivateKeyPassword = "",
|
||||
networkMapPrivateKeyPassword = "",
|
||||
rootPrivateKeyPassword = "",
|
||||
keyGroup = "DEV.DOORMAN",
|
||||
validDays = 3650
|
||||
))
|
||||
}
|
||||
|
||||
private fun makeTestDataSourceProperties(): Properties {
|
||||
val props = Properties()
|
||||
props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
|
||||
props.setProperty("dataSource.url", "jdbc:h2:tcp://$HOST:$H2_TCP_PORT/mem:$DB_NAME;DB_CLOSE_DELAY=-1")
|
||||
props.setProperty("dataSource.user", "sa")
|
||||
props.setProperty("dataSource.password", "")
|
||||
return props
|
||||
}
|
@ -22,27 +22,25 @@ import net.corda.nodeapi.internal.createDevNodeCa
|
||||
import net.corda.nodeapi.internal.crypto.*
|
||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||
import net.corda.testing.ALICE_NAME
|
||||
import net.corda.testing.BOB_NAME
|
||||
import net.corda.testing.CHARLIE_NAME
|
||||
import net.corda.testing.SerializationEnvironmentRule
|
||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||
import net.corda.testing.internal.rigorousMock
|
||||
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
|
||||
import org.h2.tools.Server
|
||||
import org.junit.*
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import java.net.URL
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.*
|
||||
import javax.persistence.PersistenceException
|
||||
import kotlin.concurrent.scheduleAtFixedRate
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class SigningServiceIntegrationTest {
|
||||
companion object {
|
||||
val H2_TCP_PORT = "8092"
|
||||
val HOST = "localhost"
|
||||
val DB_NAME = "test_db"
|
||||
private val HOST = "localhost"
|
||||
private val DB_NAME = "test_db"
|
||||
}
|
||||
|
||||
@Rule
|
||||
@ -92,7 +90,7 @@ class SigningServiceIntegrationTest {
|
||||
val database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true))
|
||||
|
||||
NetworkManagementServer().use { server ->
|
||||
server.start(NetworkHostAndPort(HOST, 0), database, networkMapServiceParameter = null, doormanServiceParameter = DoormanConfig(approveAll = true, approveInterval = 2.seconds.toMillis(), jiraConfig = null), updateNetworkParameters = null)
|
||||
server.start(NetworkHostAndPort(HOST, 0), database, doormanServiceParameter = DoormanConfig(approveAll = true, approveInterval = 2.seconds.toMillis(), jiraConfig = null), startNetworkMap = null)
|
||||
val doormanHostAndPort = server.hostAndPort
|
||||
// Start Corda network registration.
|
||||
val config = createConfig().also {
|
||||
@ -131,51 +129,6 @@ class SigningServiceIntegrationTest {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Piece of code is purely for demo purposes and should not be considered as actual test (therefore it is ignored).
|
||||
* Its purpose is to produce 3 CSRs and wait (polling Doorman) for external signature.
|
||||
* The use of the jUnit testing framework was chosen due to the convenience reasons: mocking, tempFolder storage.
|
||||
* It is meant to be run together with the [DemoMain.main] method, which executes HSM signing service.
|
||||
* The split is done due to the limited console support while executing tests and inability to capture user's input there.
|
||||
*
|
||||
*/
|
||||
@Ignore
|
||||
@Test
|
||||
fun `DEMO - Create CSR and poll`() {
|
||||
//Start doorman server
|
||||
val database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true))
|
||||
|
||||
NetworkManagementServer().use { server ->
|
||||
server.start(NetworkHostAndPort(HOST, 0), database, networkMapServiceParameter = null, doormanServiceParameter = DoormanConfig(approveAll = true, approveInterval = 2.seconds.toMillis(), jiraConfig = null), updateNetworkParameters = null)
|
||||
thread(start = true, isDaemon = true) {
|
||||
val h2ServerArgs = arrayOf("-tcpPort", H2_TCP_PORT, "-tcpAllowOthers")
|
||||
Server.createTcpServer(*h2ServerArgs).start()
|
||||
}
|
||||
|
||||
// Start Corda network registration.
|
||||
(1..3).map { num ->
|
||||
thread(start = true) {
|
||||
// Start Corda network registration.
|
||||
val config = createConfig().also {
|
||||
doReturn(when (num) {
|
||||
1 -> ALICE_NAME
|
||||
2 -> BOB_NAME
|
||||
3 -> CHARLIE_NAME
|
||||
else -> throw IllegalArgumentException("Unrecognised option")
|
||||
}).whenever(it).myLegalName
|
||||
doReturn(URL("http://$HOST:${server.hostAndPort.port}")).whenever(it).compatibilityZoneURL
|
||||
}
|
||||
config.certificatesDirectory.createDirectories()
|
||||
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also {
|
||||
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCaCert)
|
||||
it.save(config.trustStoreFile, config.trustStorePassword)
|
||||
}
|
||||
NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore()
|
||||
}
|
||||
}.map { it.join() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun createConfig(): NodeConfiguration {
|
||||
return rigorousMock<NodeConfiguration>().also {
|
||||
doReturn(tempFolder.root.toPath()).whenever(it).baseDirectory
|
||||
@ -198,5 +151,3 @@ class SigningServiceIntegrationTest {
|
||||
return props
|
||||
}
|
||||
}
|
||||
|
||||
internal fun makeNotInitialisingTestDatabaseProperties() = DatabaseConfig(runMigration = false)
|
||||
|
@ -1,9 +1,9 @@
|
||||
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.crypto.SignedData
|
||||
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||
|
||||
/**
|
||||
* Data access object interface for NetworkMap persistence layer
|
||||
@ -34,7 +34,7 @@ interface NetworkMapStorage {
|
||||
* 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.
|
||||
*/
|
||||
fun getSignedNetworkParameters(hash: SecureHash): SignedData<NetworkParameters>?
|
||||
fun getSignedNetworkParameters(hash: SecureHash): SignedNetworkParameters?
|
||||
|
||||
/**
|
||||
* Retrieve network map parameters.
|
||||
|
@ -1,17 +1,16 @@
|
||||
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.DigitalSignature
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.SignedData
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.nodeapi.internal.network.NetworkMap
|
||||
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
|
||||
/**
|
||||
@ -40,8 +39,8 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence, privat
|
||||
database.transaction {
|
||||
val networkMapEntity = NetworkMapEntity(
|
||||
networkMap = signedNetworkMap.raw.bytes,
|
||||
signature = signedNetworkMap.signature.signatureBytes,
|
||||
certificate = signedNetworkMap.signature.by.encoded
|
||||
signature = signedNetworkMap.sig.bytes,
|
||||
certificate = signedNetworkMap.sig.by.encoded
|
||||
)
|
||||
session.save(networkMapEntity)
|
||||
}
|
||||
@ -49,10 +48,10 @@ 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): SignedData<NetworkParameters>? {
|
||||
override fun getSignedNetworkParameters(hash: SecureHash): SignedNetworkParameters? {
|
||||
val netParamsBytes = getNetworkParametersEntity(hash.toString())?.parametersBytes ?: return null
|
||||
val sigWithCert = localSigner!!.sign(netParamsBytes)
|
||||
return SignedData(SerializedBytes(netParamsBytes), DigitalSignature.WithKey(sigWithCert.by.publicKey, sigWithCert.signatureBytes))
|
||||
val sigWithCert = localSigner!!.signBytes(netParamsBytes)
|
||||
return SignedNetworkParameters(SerializedBytes(netParamsBytes), sigWithCert)
|
||||
}
|
||||
|
||||
override fun getNodeInfoHashes(certificateStatus: CertificateStatus): List<SecureHash> {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.r3.corda.networkmanage.common.persistence.entity
|
||||
|
||||
import net.corda.core.internal.DigitalSignatureWithCert
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.network.DigitalSignatureWithCert
|
||||
import javax.persistence.*
|
||||
|
||||
@Entity
|
||||
@ -24,7 +24,7 @@ class NetworkMapEntity(
|
||||
val certificate: ByteArray
|
||||
) {
|
||||
/**
|
||||
* Deserializes NetworkMapEntity.signatureBytes into the [SignatureAndCertPath] instance
|
||||
* Deserializes NetworkMapEntity.signatureBytes into the [DigitalSignatureWithCert] instance
|
||||
*/
|
||||
fun signatureAndCertificate(): DigitalSignatureWithCert {
|
||||
return DigitalSignatureWithCert(X509CertificateFactory().generateCertificate(certificate.inputStream()), signature)
|
||||
|
@ -2,9 +2,9 @@ package com.r3.corda.networkmanage.common.signer
|
||||
|
||||
import com.r3.corda.networkmanage.common.persistence.CertificateStatus
|
||||
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
||||
import net.corda.core.internal.SignedDataWithCert
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.nodeapi.internal.network.NetworkMap
|
||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||
|
||||
class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private val signer: Signer) {
|
||||
/**
|
||||
@ -14,12 +14,10 @@ class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private
|
||||
val currentSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
|
||||
val nodeInfoHashes = networkMapStorage.getNodeInfoHashes(CertificateStatus.VALID)
|
||||
val networkParameters = networkMapStorage.getLatestNetworkParameters()
|
||||
val networkMap = NetworkMap(nodeInfoHashes, networkParameters.serialize().hash)
|
||||
// We wan only check if the data structure is same.
|
||||
if (networkMap != currentSignedNetworkMap?.verified(null)) {
|
||||
val digitalSignature = signer.sign(networkMap.serialize().bytes)
|
||||
val signedHashedNetworkMap = SignedNetworkMap(networkMap.serialize(), digitalSignature)
|
||||
networkMapStorage.saveNetworkMap(signedHashedNetworkMap)
|
||||
val serialisedNetworkMap = NetworkMap(nodeInfoHashes, networkParameters.serialize().hash).serialize()
|
||||
if (serialisedNetworkMap != currentSignedNetworkMap?.raw) {
|
||||
val newSignedNetworkMap = SignedDataWithCert(serialisedNetworkMap, signer.signBytes(serialisedNetworkMap.bytes))
|
||||
networkMapStorage.saveNetworkMap(newSignedNetworkMap)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +1,24 @@
|
||||
package com.r3.corda.networkmanage.common.signer
|
||||
|
||||
import net.corda.nodeapi.internal.network.DigitalSignatureWithCert
|
||||
import net.corda.core.internal.DigitalSignatureWithCert
|
||||
import net.corda.core.internal.SignedDataWithCert
|
||||
import net.corda.core.serialization.serialize
|
||||
|
||||
/**
|
||||
* An interface for arbitrary data signing functionality.
|
||||
*/
|
||||
interface Signer {
|
||||
/**
|
||||
* Signs given [data]. The signing key selction strategy is left to the implementing class.
|
||||
* @return [SignatureAndCertPath] that encapsulates the signature and the certificate path used in the signing process.
|
||||
* Signs given bytes. The signing key selction 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
|
||||
*/
|
||||
fun sign(data: ByteArray): DigitalSignatureWithCert
|
||||
fun signBytes(data: ByteArray): DigitalSignatureWithCert
|
||||
|
||||
fun <T : Any> signObject(obj: T): SignedDataWithCert<T> {
|
||||
val serialised = obj.serialize()
|
||||
return SignedDataWithCert(serialised, signBytes(serialised.bytes))
|
||||
}
|
||||
}
|
||||
|
||||
class AuthenticationException : Exception()
|
||||
|
@ -5,15 +5,18 @@ import com.typesafe.config.Config
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import joptsimple.ArgumentAcceptingOptionSpec
|
||||
import joptsimple.OptionParser
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.internal.SignedDataWithCert
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.network.DigitalSignatureWithCert
|
||||
import org.bouncycastle.cert.X509CertificateHolder
|
||||
import net.corda.nodeapi.internal.network.NetworkMap
|
||||
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||
import java.security.PublicKey
|
||||
import java.security.cert.CertPath
|
||||
import java.security.cert.Certificate
|
||||
import java.security.cert.X509Certificate
|
||||
|
||||
// TODO These should be defined in node-api
|
||||
typealias SignedNetworkParameters = SignedDataWithCert<NetworkParameters>
|
||||
typealias SignedNetworkMap = SignedDataWithCert<NetworkMap>
|
||||
|
||||
// TODO: replace this with Crypto.hash when its available.
|
||||
/**
|
||||
@ -39,15 +42,10 @@ fun Array<out String>.toConfigWithOptions(registerOptions: OptionParser.() -> Un
|
||||
|
||||
class ShowHelpException(val parser: OptionParser, val errorMessage: String? = null) : Exception()
|
||||
|
||||
// TODO Remove this as we already have InternalUtils.cert
|
||||
fun X509CertificateHolder.toX509Certificate(): X509Certificate = X509CertificateFactory().generateCertificate(encoded.inputStream())
|
||||
|
||||
fun buildCertPath(vararg certificates: Certificate): CertPath = X509CertificateFactory().delegate.generateCertPath(certificates.asList())
|
||||
|
||||
fun buildCertPath(certPathBytes: ByteArray): CertPath = X509CertificateFactory().delegate.generateCertPath(certPathBytes.inputStream())
|
||||
|
||||
fun DigitalSignature.WithKey.withCert(cert: X509Certificate): DigitalSignatureWithCert = DigitalSignatureWithCert(cert, bytes)
|
||||
|
||||
private fun String.toCamelcase(): String {
|
||||
return if (contains('_') || contains('-')) {
|
||||
CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, this.replace("-", "_"))
|
||||
|
@ -53,10 +53,11 @@ data class DoormanConfig(val approveAll: Boolean = false,
|
||||
val approveInterval: Long = NetworkManagementServerParameters.DEFAULT_APPROVE_INTERVAL.toMillis())
|
||||
|
||||
data class NetworkMapConfig(val cacheTimeout: Long,
|
||||
// TODO: Move signing to signing server.
|
||||
// TODO: Move signing to signing server.
|
||||
val signInterval: Long = NetworkManagementServerParameters.DEFAULT_SIGN_INTERVAL.toMillis())
|
||||
|
||||
enum class Mode {
|
||||
// TODO CA_KEYGEN now also generates the nework map cert, so it should be renamed.
|
||||
DOORMAN, CA_KEYGEN, ROOT_KEYGEN
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,10 @@ import com.r3.corda.networkmanage.doorman.signer.LocalSigner
|
||||
import com.r3.corda.networkmanage.doorman.webservice.MonitoringWebService
|
||||
import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService
|
||||
import com.r3.corda.networkmanage.doorman.webservice.RegistrationWebService
|
||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters.Companion.DEFAULT_CSR_CERTIFICATE_NAME
|
||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters.Companion.DEFAULT_NETWORK_MAP_CERTIFICATE_NAME
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SignatureScheme
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.createDirectories
|
||||
import net.corda.core.internal.div
|
||||
@ -34,6 +37,7 @@ import java.time.Instant
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
@ -130,17 +134,16 @@ class NetworkManagementServer : Closeable {
|
||||
|
||||
fun start(hostAndPort: NetworkHostAndPort,
|
||||
database: CordaPersistence,
|
||||
signer: LocalSigner? = null,
|
||||
updateNetworkParameters: NetworkParameters?,
|
||||
networkMapServiceParameter: NetworkMapConfig?,
|
||||
doormanServiceParameter: DoormanConfig?) {
|
||||
|
||||
doormanSigner: LocalSigner? = null,
|
||||
doormanServiceParameter: DoormanConfig?, // TODO Doorman config shouldn't be optional as the doorman is always required to run
|
||||
startNetworkMap: NetworkMapStartParams?
|
||||
) {
|
||||
val services = mutableListOf<Any>()
|
||||
val serverStatus = NetworkManagementServerStatus()
|
||||
|
||||
// TODO: move signing to signing server.
|
||||
networkMapServiceParameter?.let { services += getNetworkMapService(it, database, signer, updateNetworkParameters) }
|
||||
doormanServiceParameter?.let { services += getDoormanService(it, database, signer, serverStatus) }
|
||||
startNetworkMap?.let { services += getNetworkMapService(it.config, database, it.signer, it.updateNetworkParameters) }
|
||||
doormanServiceParameter?.let { services += getDoormanService(it, database, doormanSigner, serverStatus) }
|
||||
|
||||
require(services.isNotEmpty()) { "No service created, please provide at least one service config." }
|
||||
|
||||
@ -150,11 +153,13 @@ class NetworkManagementServer : Closeable {
|
||||
val webServer = NetworkManagementWebServer(hostAndPort, *services.toTypedArray())
|
||||
webServer.start()
|
||||
|
||||
doOnClose += { webServer.close() }
|
||||
doOnClose += webServer::close
|
||||
this.hostAndPort = webServer.hostAndPort
|
||||
}
|
||||
}
|
||||
|
||||
data class NetworkMapStartParams(val signer: LocalSigner?, val updateNetworkParameters: NetworkParameters?, val config: NetworkMapConfig)
|
||||
|
||||
data class NetworkManagementServerStatus(var serverStartTime: Instant = Instant.now(), var lastRequestCheckTime: Instant? = null)
|
||||
|
||||
/** Read password from console, do a readLine instead if console is null (e.g. when debugging in IDE). */
|
||||
@ -203,58 +208,77 @@ fun generateRootKeyPair(rootStoreFile: Path, rootKeystorePass: String?, rootPriv
|
||||
println(loadKeyStore(rootStoreFile, rootKeystorePassword).getCertificate(X509Utilities.CORDA_ROOT_CA).publicKey)
|
||||
}
|
||||
|
||||
fun generateCAKeyPair(keystoreFile: Path, rootStoreFile: Path, rootKeystorePass: String?, rootPrivateKeyPass: String?, keystorePass: String?, caPrivateKeyPass: String?) {
|
||||
println("Generating Intermediate CA keypair and certificate using root keystore $rootStoreFile.")
|
||||
fun generateSigningKeyPairs(keystoreFile: Path, rootStoreFile: Path, rootKeystorePass: String?, rootPrivateKeyPass: String?, keystorePass: String?, caPrivateKeyPass: String?) {
|
||||
println("Generating intermediate and network map key pairs and certificates using root key store $rootStoreFile.")
|
||||
// Get password from console if not in config.
|
||||
val rootKeystorePassword = rootKeystorePass ?: readPassword("Root Keystore Password: ")
|
||||
val rootPrivateKeyPassword = rootPrivateKeyPass ?: readPassword("Root Private Key Password: ")
|
||||
val rootKeystorePassword = rootKeystorePass ?: readPassword("Root key store password: ")
|
||||
val rootPrivateKeyPassword = rootPrivateKeyPass ?: readPassword("Root private key password: ")
|
||||
val rootKeyStore = loadKeyStore(rootStoreFile, rootKeystorePassword)
|
||||
|
||||
val rootKeyAndCert = rootKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_ROOT_CA, rootPrivateKeyPassword)
|
||||
val rootKeyPairAndCert = rootKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_ROOT_CA, rootPrivateKeyPassword)
|
||||
|
||||
val keystorePassword = keystorePass ?: readPassword("Keystore Password: ")
|
||||
val caPrivateKeyPassword = caPrivateKeyPass ?: readPassword("CA Private Key Password: ")
|
||||
val keyStorePassword = keystorePass ?: readPassword("Key store Password: ")
|
||||
val privateKeyPassword = caPrivateKeyPass ?: readPassword("Private key Password: ")
|
||||
// Ensure folder exists.
|
||||
keystoreFile.parent.createDirectories()
|
||||
val keyStore = loadOrCreateKeyStore(keystoreFile, keystorePassword)
|
||||
val keyStore = loadOrCreateKeyStore(keystoreFile, keyStorePassword)
|
||||
|
||||
if (keyStore.containsAlias(X509Utilities.CORDA_INTERMEDIATE_CA)) {
|
||||
val oldKey = loadOrCreateKeyStore(keystoreFile, rootKeystorePassword).getCertificate(X509Utilities.CORDA_INTERMEDIATE_CA).publicKey
|
||||
println("Key ${X509Utilities.CORDA_INTERMEDIATE_CA} already exists in keystore, process will now terminate.")
|
||||
println(oldKey)
|
||||
exitProcess(1)
|
||||
fun storeCertIfAbsent(alias: String, certificateType: CertificateType, subject: X500Principal, signatureScheme: SignatureScheme) {
|
||||
if (keyStore.containsAlias(alias)) {
|
||||
println("$alias already exists in keystore:")
|
||||
println(keyStore.getCertificate(alias))
|
||||
return
|
||||
}
|
||||
|
||||
val keyPair = Crypto.generateKeyPair(signatureScheme)
|
||||
val cert = X509Utilities.createCertificate(
|
||||
certificateType,
|
||||
rootKeyPairAndCert.certificate,
|
||||
rootKeyPairAndCert.keyPair,
|
||||
subject,
|
||||
keyPair.public
|
||||
)
|
||||
keyStore.addOrReplaceKey(
|
||||
alias,
|
||||
keyPair.private,
|
||||
privateKeyPassword.toCharArray(),
|
||||
arrayOf(cert, rootKeyPairAndCert.certificate)
|
||||
)
|
||||
keyStore.save(keystoreFile, keyStorePassword)
|
||||
|
||||
println("$certificateType key pair and certificate stored in $keystoreFile.")
|
||||
println(cert)
|
||||
}
|
||||
|
||||
val intermediateKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val intermediateCert = X509Utilities.createCertificate(
|
||||
storeCertIfAbsent(
|
||||
DEFAULT_CSR_CERTIFICATE_NAME,
|
||||
CertificateType.INTERMEDIATE_CA,
|
||||
rootKeyAndCert.certificate,
|
||||
rootKeyAndCert.keyPair,
|
||||
CordaX500Name(commonName = "Corda Intermediate CA", organisation = "R3 Ltd", organisationUnit = "Corda", locality = "London", country = "GB", state = null).x500Principal,
|
||||
intermediateKeyPair.public
|
||||
)
|
||||
keyStore.addOrReplaceKey(
|
||||
X509Utilities.CORDA_INTERMEDIATE_CA,
|
||||
intermediateKeyPair.private,
|
||||
caPrivateKeyPassword.toCharArray(),
|
||||
arrayOf(intermediateCert, rootKeyAndCert.certificate)
|
||||
)
|
||||
keyStore.save(keystoreFile, keystorePassword)
|
||||
println("Intermediate CA keypair and certificate stored in $keystoreFile.")
|
||||
println(loadKeyStore(keystoreFile, keystorePassword).getCertificate(X509Utilities.CORDA_INTERMEDIATE_CA).publicKey)
|
||||
X500Principal("CN=Corda Intermediate CA,OU=Corda,O=R3 Ltd,L=London,C=GB"),
|
||||
X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
|
||||
storeCertIfAbsent(
|
||||
DEFAULT_NETWORK_MAP_CERTIFICATE_NAME,
|
||||
CertificateType.NETWORK_MAP,
|
||||
X500Principal("CN=Corda Network Map,OU=Corda,O=R3 Ltd,L=London,C=GB"),
|
||||
Crypto.EDDSA_ED25519_SHA512)
|
||||
}
|
||||
|
||||
|
||||
private fun buildLocalSigner(parameters: NetworkManagementServerParameters): LocalSigner? {
|
||||
return parameters.keystorePath?.let {
|
||||
// Get password from console if not in config.
|
||||
val keystorePassword = parameters.keystorePassword ?: readPassword("Keystore Password: ")
|
||||
val caPrivateKeyPassword = parameters.caPrivateKeyPassword ?: readPassword("CA Private Key Password: ")
|
||||
val keystore = loadOrCreateKeyStore(parameters.keystorePath, keystorePassword)
|
||||
val caKeyPair = keystore.getKeyPair(X509Utilities.CORDA_INTERMEDIATE_CA, caPrivateKeyPassword)
|
||||
val caCertPath = keystore.getCertificateChain(X509Utilities.CORDA_INTERMEDIATE_CA).map { it as X509Certificate }
|
||||
LocalSigner(caKeyPair, caCertPath.toTypedArray())
|
||||
private fun buildLocalSigners(parameters: NetworkManagementServerParameters): Pair<LocalSigner, LocalSigner>? {
|
||||
if (parameters.keystorePath == null) return null
|
||||
|
||||
// Get password from console if not in config.
|
||||
val keyStorePassword = parameters.keystorePassword ?: readPassword("Key store password: ")
|
||||
val privateKeyPassword = parameters.caPrivateKeyPassword ?: readPassword("Private key password: ")
|
||||
val keyStore = loadOrCreateKeyStore(parameters.keystorePath, keyStorePassword)
|
||||
|
||||
val (doormanSigner, networkMapSigner) = listOf(DEFAULT_CSR_CERTIFICATE_NAME, DEFAULT_NETWORK_MAP_CERTIFICATE_NAME).map {
|
||||
val keyPair = keyStore.getKeyPair(it, privateKeyPassword)
|
||||
val certPath = keyStore.getCertificateChain(it).map { it as X509Certificate }
|
||||
LocalSigner(keyPair, certPath.toTypedArray())
|
||||
}
|
||||
|
||||
return Pair(doormanSigner, networkMapSigner)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -278,7 +302,7 @@ fun main(args: Array<String>) {
|
||||
rootStorePath ?: throw IllegalArgumentException("The 'rootStorePath' parameter must be specified when generating keys!"),
|
||||
rootKeystorePassword,
|
||||
rootPrivateKeyPassword)
|
||||
Mode.CA_KEYGEN -> generateCAKeyPair(
|
||||
Mode.CA_KEYGEN -> generateSigningKeyPairs(
|
||||
keystorePath ?: throw IllegalArgumentException("The 'keystorePath' parameter must be specified when generating keys!"),
|
||||
rootStorePath ?: throw IllegalArgumentException("The 'rootStorePath' parameter must be specified when generating keys!"),
|
||||
rootKeystorePassword,
|
||||
@ -289,18 +313,24 @@ fun main(args: Array<String>) {
|
||||
initialiseSerialization()
|
||||
val database = configureDatabase(dataSourceProperties)
|
||||
// TODO: move signing to signing server.
|
||||
val signer = buildLocalSigner(this)
|
||||
val localSigners = buildLocalSigners(this)
|
||||
|
||||
if (signer != null) {
|
||||
println("Starting network management services with local signer.")
|
||||
if (localSigners != null) {
|
||||
println("Starting network management services with local signing")
|
||||
}
|
||||
|
||||
val networkManagementServer = NetworkManagementServer()
|
||||
val networkParameter = updateNetworkParameters?.let {
|
||||
println("Parsing network parameter from '${it.fileName}'...")
|
||||
val networkParameters = updateNetworkParameters?.let {
|
||||
// TODO This check shouldn't be needed. Fix up the config design.
|
||||
requireNotNull(networkMapConfig) { "'networkMapConfig' config is required for applying network parameters" }
|
||||
println("Parsing network parameters from '${it.toAbsolutePath()}'...")
|
||||
parseNetworkParametersFrom(it)
|
||||
}
|
||||
networkManagementServer.start(NetworkHostAndPort(host, port), database, signer, networkParameter, networkMapConfig, doormanConfig)
|
||||
val networkMapStartParams = networkMapConfig?.let {
|
||||
NetworkMapStartParams(localSigners?.second, networkParameters, it)
|
||||
}
|
||||
|
||||
networkManagementServer.start(NetworkHostAndPort(host, port), database, localSigners?.first, doormanConfig, networkMapStartParams)
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(thread(start = false) {
|
||||
networkManagementServer.close()
|
||||
|
@ -2,11 +2,10 @@ package com.r3.corda.networkmanage.doorman.signer
|
||||
|
||||
import com.r3.corda.networkmanage.common.signer.Signer
|
||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||
import com.r3.corda.networkmanage.common.utils.withCert
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.internal.DigitalSignatureWithCert
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.network.DigitalSignatureWithCert
|
||||
import org.bouncycastle.asn1.x509.GeneralName
|
||||
import org.bouncycastle.asn1.x509.GeneralSubtree
|
||||
import org.bouncycastle.asn1.x509.NameConstraints
|
||||
@ -21,7 +20,9 @@ import javax.security.auth.x500.X500Principal
|
||||
* The [LocalSigner] class signs [PKCS10CertificationRequest] using provided CA key pair and certificate path.
|
||||
* This is intended to be used in testing environment where hardware signing module is not available.
|
||||
*/
|
||||
class LocalSigner(private val caKeyPair: KeyPair, private val caCertPath: Array<X509Certificate>) : Signer {
|
||||
//TODO Use a list instead of array
|
||||
class LocalSigner(private val signingKeyPair: KeyPair, private val signingCertPath: Array<X509Certificate>) : Signer {
|
||||
// TODO This doesn't belong in this class
|
||||
fun createSignedClientCertificate(certificationRequest: PKCS10CertificationRequest): CertPath {
|
||||
// The sub certs issued by the client must satisfy this directory name (or legal name in Corda) constraints, sub certs' directory name must be within client CA's name's subtree,
|
||||
// please see [sun.security.x509.X500Name.isWithinSubtree()] for more information.
|
||||
@ -33,15 +34,15 @@ class LocalSigner(private val caKeyPair: KeyPair, private val caCertPath: Array<
|
||||
arrayOf())
|
||||
val nodeCaCert = X509Utilities.createCertificate(
|
||||
CertificateType.NODE_CA,
|
||||
caCertPath[0],
|
||||
caKeyPair,
|
||||
signingCertPath[0],
|
||||
signingKeyPair,
|
||||
X500Principal(request.subject.encoded),
|
||||
request.publicKey,
|
||||
nameConstraints = nameConstraints)
|
||||
return buildCertPath(nodeCaCert, *caCertPath)
|
||||
return buildCertPath(nodeCaCert, *signingCertPath)
|
||||
}
|
||||
|
||||
override fun sign(data: ByteArray): DigitalSignatureWithCert {
|
||||
return caKeyPair.sign(data).withCert(caCertPath.first())
|
||||
override fun signBytes(data: ByteArray): DigitalSignatureWithCert {
|
||||
return DigitalSignatureWithCert(signingCertPath[0], Crypto.doSign(signingKeyPair.private, data))
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import com.google.common.cache.LoadingCache
|
||||
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.doorman.NetworkMapConfig
|
||||
import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService.Companion.NETWORK_MAP_PATH
|
||||
import net.corda.core.crypto.SecureHash
|
||||
@ -15,7 +16,6 @@ import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||
import java.io.InputStream
|
||||
import java.security.InvalidKeyException
|
||||
import java.security.SignatureException
|
||||
@ -77,9 +77,9 @@ class NodeInfoWebService(private val nodeInfoStorage: NodeInfoStorage,
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("network-parameter/{netParamsHash}") // TODO Fix path to be /network-parameters
|
||||
fun getNetworkParameters(@PathParam("netParamsHash") netParamsHash: String): Response {
|
||||
val signedNetParams = networkMapStorage.getSignedNetworkParameters(SecureHash.parse(netParamsHash))
|
||||
@Path("network-parameters/{hash}")
|
||||
fun getNetworkParameters(@PathParam("hash") hash: String): Response {
|
||||
val signedNetParams = networkMapStorage.getSignedNetworkParameters(SecureHash.parse(hash))
|
||||
return createResponse(signedNetParams)
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ data class Parameters(val dataSourceProperties: Properties,
|
||||
val DEFAULT_KEY_FILE_PATH: Path? = null //Paths.get("/Users/michalkit/WinDev1706Eval/Shared/TEST4.key")
|
||||
val DEFAULT_KEY_FILE_PASSWORD: String? = null
|
||||
val DEFAULT_AUTO_USERNAME: String? = null
|
||||
val DEFAULT_NETWORK_MAP_CERTIFICATE_NAME = "cordaintermediateca_nm"
|
||||
val DEFAULT_NETWORK_MAP_CERTIFICATE_NAME = "cordaintermediateca_nm" // TODO Change the value to "cordanetworkmap" since this is not a CA
|
||||
val DEFAULT_SIGN_INTERVAL = 600L // in seconds (10 minutes)
|
||||
}
|
||||
}
|
||||
|
@ -4,16 +4,15 @@ import com.google.common.util.concurrent.MoreExecutors
|
||||
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
||||
import com.r3.corda.networkmanage.common.signer.NetworkMapSigner
|
||||
import com.r3.corda.networkmanage.common.signer.Signer
|
||||
import com.r3.corda.networkmanage.common.utils.withCert
|
||||
import com.r3.corda.networkmanage.hsm.authentication.Authenticator
|
||||
import com.r3.corda.networkmanage.hsm.utils.X509Utilities
|
||||
import com.r3.corda.networkmanage.hsm.utils.X509Utilities.getAndInitializeKeyStore
|
||||
import com.r3.corda.networkmanage.hsm.utils.X509Utilities.signData
|
||||
import com.r3.corda.networkmanage.hsm.utils.X509Utilities.verify
|
||||
import net.corda.core.internal.DigitalSignatureWithCert
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.core.utilities.minutes
|
||||
import net.corda.nodeapi.internal.network.DigitalSignatureWithCert
|
||||
import java.security.KeyPair
|
||||
import java.security.PrivateKey
|
||||
import java.security.Signature
|
||||
import java.security.cert.X509Certificate
|
||||
import java.time.Duration
|
||||
import java.util.concurrent.Executors
|
||||
@ -24,6 +23,7 @@ import java.util.concurrent.TimeUnit
|
||||
* Encapsulates logic for periodic network map signing execution.
|
||||
* It uses HSM as the signing entity with keys and certificates specified at the construction time.
|
||||
*/
|
||||
// TODO Rename this to HsmSigner
|
||||
class HsmNetworkMapSigner(networkMapStorage: NetworkMapStorage,
|
||||
private val caCertificateKeyName: String,
|
||||
private val caPrivateKeyPass: String,
|
||||
@ -40,6 +40,7 @@ class HsmNetworkMapSigner(networkMapStorage: NetworkMapStorage,
|
||||
private val networkMapSigner = NetworkMapSigner(networkMapStorage, this)
|
||||
private lateinit var scheduledExecutor: ScheduledExecutorService
|
||||
|
||||
// TODO This doesn't belong in this class
|
||||
fun start(): HsmNetworkMapSigner {
|
||||
val signingPeriodMillis = signingPeriod.toMillis()
|
||||
scheduledExecutor = Executors.newSingleThreadScheduledExecutor()
|
||||
@ -60,14 +61,18 @@ class HsmNetworkMapSigner(networkMapStorage: NetworkMapStorage,
|
||||
/**
|
||||
* Signs given data using [CryptoServerJCE.CryptoServerProvider], which connects to the underlying HSM.
|
||||
*/
|
||||
override fun sign(data: ByteArray): DigitalSignatureWithCert {
|
||||
override fun signBytes(data: ByteArray): DigitalSignatureWithCert {
|
||||
return authenticator.connectAndAuthenticate { provider, _ ->
|
||||
val keyStore = getAndInitializeKeyStore(provider)
|
||||
val caCertificateChain = keyStore.getCertificateChain(caCertificateKeyName)
|
||||
val caKey = keyStore.getKey(caCertificateKeyName, caPrivateKeyPass.toCharArray()) as PrivateKey
|
||||
val signature = signData(data, KeyPair(caCertificateChain.first().publicKey, caKey), provider)
|
||||
verify(data, signature, caCertificateChain.first().publicKey)
|
||||
signature.withCert(caCertificateChain[0] as X509Certificate)
|
||||
val signature = Signature.getInstance(X509Utilities.SIGNATURE_ALGORITHM, provider).run {
|
||||
initSign(caKey)
|
||||
update(data)
|
||||
sign()
|
||||
}
|
||||
verify(data, signature, caCertificateChain[0].publicKey)
|
||||
DigitalSignatureWithCert(caCertificateChain[0] as X509Certificate, signature)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.r3.corda.networkmanage.hsm.utils
|
||||
|
||||
import CryptoServerJCE.CryptoServerProvider
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.x500Name
|
||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
@ -268,27 +267,14 @@ object X509Utilities {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign data with the given private key
|
||||
*/
|
||||
fun signData(data: ByteArray,
|
||||
keyPair: KeyPair,
|
||||
provider: Provider,
|
||||
signatureAlgorithm: String = SIGNATURE_ALGORITHM): DigitalSignature.WithKey {
|
||||
val signer = Signature.getInstance(signatureAlgorithm, provider)
|
||||
signer.initSign(keyPair.private)
|
||||
signer.update(data)
|
||||
return DigitalSignature.WithKey(keyPair.public, signer.sign())
|
||||
}
|
||||
|
||||
fun verify(data: ByteArray,
|
||||
signature: DigitalSignature,
|
||||
signature: ByteArray,
|
||||
publicKey: PublicKey,
|
||||
signatureAlgorithm: String = SIGNATURE_ALGORITHM) {
|
||||
val verify = Signature.getInstance(signatureAlgorithm)
|
||||
verify.initVerify(publicKey)
|
||||
verify.update(data)
|
||||
require(verify.verify(signature.bytes)) { "Signature didn't independently verify" }
|
||||
require(verify.verify(signature)) { "Signature didn't independently verify" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,16 +1,14 @@
|
||||
package com.r3.corda.networkmanage.common.persistence
|
||||
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.common.utils.withCert
|
||||
import com.r3.corda.networkmanage.doorman.signer.LocalSigner
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||
import net.corda.core.internal.signWithCert
|
||||
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.network.NetworkMap
|
||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
@ -31,15 +29,15 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
||||
private lateinit var requestStorage: PersistentCertificateRequestStorage
|
||||
|
||||
private lateinit var rootCaCert: X509Certificate
|
||||
private lateinit var intermediateCa: CertificateAndKeyPair
|
||||
private lateinit var networkMapCa: CertificateAndKeyPair
|
||||
|
||||
@Before
|
||||
fun startDb() {
|
||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||
val (rootCa) = createDevIntermediateCaCertPath()
|
||||
rootCaCert = rootCa.certificate
|
||||
this.intermediateCa = intermediateCa
|
||||
networkMapCa = createDevNetworkMapCa(rootCa)
|
||||
persistence = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true))
|
||||
networkMapStorage = PersistentNetworkMapStorage(persistence, LocalSigner(intermediateCa.keyPair, arrayOf(intermediateCa.certificate, rootCaCert)))
|
||||
networkMapStorage = PersistentNetworkMapStorage(persistence, LocalSigner(networkMapCa.keyPair, arrayOf(networkMapCa.certificate, rootCaCert)))
|
||||
nodeInfoStorage = PersistentNodeInfoStorage(persistence)
|
||||
requestStorage = PersistentCertificateRequestStorage(persistence)
|
||||
}
|
||||
@ -60,9 +58,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
||||
val networkParametersHash = networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList()))
|
||||
|
||||
val networkMap = NetworkMap(listOf(nodeInfoHash), networkParametersHash)
|
||||
val serializedNetworkMap = networkMap.serialize()
|
||||
val signatureData = intermediateCa.keyPair.sign(serializedNetworkMap).withCert(intermediateCa.certificate)
|
||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
|
||||
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
||||
|
||||
// when
|
||||
networkMapStorage.saveNetworkMap(signedNetworkMap)
|
||||
@ -70,8 +66,8 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
||||
// then
|
||||
val persistedSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
|
||||
|
||||
assertEquals(signedNetworkMap.signature, persistedSignedNetworkMap?.signature)
|
||||
assertEquals(signedNetworkMap.verified(rootCaCert), persistedSignedNetworkMap?.verified(rootCaCert))
|
||||
assertEquals(signedNetworkMap.sig, persistedSignedNetworkMap?.sig)
|
||||
assertEquals(signedNetworkMap.verifiedNetworkMapCert(rootCaCert), persistedSignedNetworkMap?.verifiedNetworkMapCert(rootCaCert))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -96,9 +92,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
||||
|
||||
// Sign network map making it current network map
|
||||
val networkMap = NetworkMap(emptyList(), networkParametersHash)
|
||||
val serializedNetworkMap = networkMap.serialize()
|
||||
val signatureData = intermediateCa.keyPair.sign(serializedNetworkMap).withCert(intermediateCa.certificate)
|
||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
|
||||
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
||||
networkMapStorage.saveNetworkMap(signedNetworkMap)
|
||||
|
||||
// Create new network parameters
|
||||
@ -114,11 +108,11 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
||||
// 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 netParams = testNetworkParameters(emptyList())
|
||||
val netParamsHash = networkMapStorage.saveNetworkParameters(netParams)
|
||||
val signedNetParams = networkMapStorage.getSignedNetworkParameters(netParamsHash)
|
||||
assertThat(signedNetParams?.verified()).isEqualTo(netParams)
|
||||
assertThat(signedNetParams?.sig?.by).isEqualTo(intermediateCa.keyPair.public)
|
||||
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
|
||||
@ -135,9 +129,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
||||
// Create network parameters
|
||||
val networkParametersHash = networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList()))
|
||||
val networkMap = NetworkMap(listOf(nodeInfoHashA), networkParametersHash)
|
||||
val serializedNetworkMap = networkMap.serialize()
|
||||
val signatureData = intermediateCa.keyPair.sign(serializedNetworkMap).withCert(intermediateCa.certificate)
|
||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
|
||||
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
||||
|
||||
// Sign network map
|
||||
networkMapStorage.saveNetworkMap(signedNetworkMap)
|
||||
|
@ -3,21 +3,24 @@ package com.r3.corda.networkmanage.common.signer
|
||||
import com.nhaarman.mockito_kotlin.*
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
||||
import com.r3.corda.networkmanage.common.utils.withCert
|
||||
import com.r3.corda.networkmanage.common.utils.SignedNetworkMap
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.internal.DigitalSignatureWithCert
|
||||
import net.corda.core.internal.signWithCert
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
||||
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.verifiedNetworkMapCert
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.security.cert.X509Certificate
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class NetworkMapSignerTest : TestBase() {
|
||||
private lateinit var signer: Signer
|
||||
@ -25,13 +28,13 @@ class NetworkMapSignerTest : TestBase() {
|
||||
private lateinit var networkMapSigner: NetworkMapSigner
|
||||
|
||||
private lateinit var rootCaCert: X509Certificate
|
||||
private lateinit var intermediateCa: CertificateAndKeyPair
|
||||
private lateinit var networkMapCa: CertificateAndKeyPair
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||
val (rootCa) = createDevIntermediateCaCertPath()
|
||||
rootCaCert = rootCa.certificate
|
||||
this.intermediateCa = intermediateCa
|
||||
networkMapCa = createDevNetworkMapCa(rootCa)
|
||||
signer = mock()
|
||||
networkMapStorage = mock()
|
||||
networkMapSigner = NetworkMapSigner(networkMapStorage, signer)
|
||||
@ -42,13 +45,13 @@ class NetworkMapSignerTest : TestBase() {
|
||||
// given
|
||||
val signedNodeInfoHashes = listOf(SecureHash.randomSHA256(), SecureHash.randomSHA256())
|
||||
val networkParameters = testNetworkParameters(emptyList())
|
||||
val serializedNetworkMap = NetworkMap(signedNodeInfoHashes, SecureHash.randomSHA256()).serialize()
|
||||
whenever(networkMapStorage.getCurrentNetworkMap())
|
||||
.thenReturn(SignedNetworkMap(serializedNetworkMap, intermediateCa.keyPair.sign(serializedNetworkMap).withCert(intermediateCa.certificate)))
|
||||
val networkMap = NetworkMap(signedNodeInfoHashes, SecureHash.randomSHA256())
|
||||
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(signer.sign(any())).then {
|
||||
intermediateCa.keyPair.sign(it.arguments[0] as ByteArray).withCert(intermediateCa.certificate)
|
||||
whenever(signer.signBytes(any())).then {
|
||||
DigitalSignatureWithCert(networkMapCa.certificate, Crypto.doSign(networkMapCa.keyPair.private, it.arguments[0] as ByteArray))
|
||||
}
|
||||
|
||||
// when
|
||||
@ -60,10 +63,10 @@ class NetworkMapSignerTest : TestBase() {
|
||||
verify(networkMapStorage).getLatestNetworkParameters()
|
||||
argumentCaptor<SignedNetworkMap>().apply {
|
||||
verify(networkMapStorage).saveNetworkMap(capture())
|
||||
val networkMap = firstValue.verified(rootCaCert)
|
||||
assertEquals(networkParameters.serialize().hash, networkMap.networkParameterHash)
|
||||
assertEquals(signedNodeInfoHashes.size, networkMap.nodeInfoHashes.size)
|
||||
assertTrue(networkMap.nodeInfoHashes.containsAll(signedNodeInfoHashes))
|
||||
val capturedNetworkMap = firstValue.verifiedNetworkMapCert(rootCaCert)
|
||||
assertEquals(networkParameters.serialize().hash, capturedNetworkMap.networkParameterHash)
|
||||
assertEquals(signedNodeInfoHashes.size, capturedNetworkMap.nodeInfoHashes.size)
|
||||
assertThat(capturedNetworkMap.nodeInfoHashes).containsAll(signedNodeInfoHashes)
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,8 +76,7 @@ class NetworkMapSignerTest : TestBase() {
|
||||
val networkParameters = testNetworkParameters(emptyList())
|
||||
val networkMapParametersHash = networkParameters.serialize().bytes.sha256()
|
||||
val networkMap = NetworkMap(emptyList(), networkMapParametersHash)
|
||||
val serializedNetworkMap = networkMap.serialize()
|
||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, intermediateCa.keyPair.sign(serializedNetworkMap).withCert(intermediateCa.certificate))
|
||||
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)
|
||||
@ -94,8 +96,8 @@ class NetworkMapSignerTest : TestBase() {
|
||||
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(null)
|
||||
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList())
|
||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
|
||||
whenever(signer.sign(any())).then {
|
||||
intermediateCa.keyPair.sign(it.arguments[0] as ByteArray).withCert(intermediateCa.certificate)
|
||||
whenever(signer.signBytes(any())).then {
|
||||
DigitalSignatureWithCert(networkMapCa.certificate, Crypto.doSign(networkMapCa.keyPair.private, it.arguments[0] as ByteArray))
|
||||
}
|
||||
// when
|
||||
networkMapSigner.signNetworkMap()
|
||||
@ -106,7 +108,7 @@ class NetworkMapSignerTest : TestBase() {
|
||||
verify(networkMapStorage).getLatestNetworkParameters()
|
||||
argumentCaptor<SignedNetworkMap>().apply {
|
||||
verify(networkMapStorage).saveNetworkMap(capture())
|
||||
val networkMap = firstValue.verified(rootCaCert)
|
||||
val networkMap = firstValue.verifiedNetworkMapCert(rootCaCert)
|
||||
assertEquals(networkParameters.serialize().hash, networkMap.networkParameterHash)
|
||||
}
|
||||
}
|
||||
|
@ -5,35 +5,33 @@ import com.nhaarman.mockito_kotlin.times
|
||||
import com.nhaarman.mockito_kotlin.verify
|
||||
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
||||
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
||||
import com.r3.corda.networkmanage.common.utils.withCert
|
||||
import com.r3.corda.networkmanage.common.utils.SignedNetworkMap
|
||||
import com.r3.corda.networkmanage.common.utils.SignedNetworkParameters
|
||||
import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService
|
||||
import net.corda.core.crypto.SecureHash.Companion.randomSHA256
|
||||
import net.corda.core.crypto.SignedData
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.checkOkResponse
|
||||
import net.corda.core.internal.openHttpConnection
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.internal.responseAs
|
||||
import net.corda.core.internal.signWithCert
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.core.utilities.seconds
|
||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
import net.corda.nodeapi.internal.network.NetworkMap
|
||||
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
|
||||
import net.corda.testing.SerializationEnvironmentRule
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||
import net.corda.testing.internal.createNodeInfoAndSigned
|
||||
import org.apache.commons.io.IOUtils
|
||||
import org.assertj.core.api.Assertions.*
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.net.URL
|
||||
import java.nio.charset.Charset
|
||||
import java.security.cert.X509Certificate
|
||||
import javax.ws.rs.core.MediaType
|
||||
import kotlin.test.assertEquals
|
||||
@ -44,15 +42,15 @@ class NodeInfoWebServiceTest {
|
||||
val testSerialization = SerializationEnvironmentRule(true)
|
||||
|
||||
private lateinit var rootCaCert: X509Certificate
|
||||
private lateinit var intermediateCa: CertificateAndKeyPair
|
||||
private lateinit var networkMapCa: CertificateAndKeyPair
|
||||
|
||||
private val testNetworkMapConfig = NetworkMapConfig(10.seconds.toMillis(), 10.seconds.toMillis())
|
||||
|
||||
@Before
|
||||
fun init() {
|
||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||
val (rootCa) = createDevIntermediateCaCertPath()
|
||||
rootCaCert = rootCa.certificate
|
||||
this.intermediateCa = intermediateCa
|
||||
networkMapCa = createDevNetworkMapCa(rootCa)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -106,8 +104,7 @@ class NodeInfoWebServiceTest {
|
||||
@Test
|
||||
fun `get network map`() {
|
||||
val networkMap = NetworkMap(listOf(randomSHA256(), randomSHA256()), randomSHA256())
|
||||
val serializedNetworkMap = networkMap.serialize()
|
||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, intermediateCa.keyPair.sign(serializedNetworkMap).withCert(intermediateCa.certificate))
|
||||
val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
||||
|
||||
val networkMapStorage: NetworkMapStorage = mock {
|
||||
on { getCurrentNetworkMap() }.thenReturn(signedNetworkMap)
|
||||
@ -117,7 +114,7 @@ class NodeInfoWebServiceTest {
|
||||
it.start()
|
||||
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
|
||||
verify(networkMapStorage, times(1)).getCurrentNetworkMap()
|
||||
assertEquals(signedNetworkMapResponse.verified(rootCaCert), networkMap)
|
||||
assertEquals(signedNetworkMapResponse.verifiedNetworkMapCert(rootCaCert), networkMap)
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,33 +133,32 @@ class NodeInfoWebServiceTest {
|
||||
verify(nodeInfoStorage, times(1)).getNodeInfo(nodeInfoHash)
|
||||
assertEquals(nodeInfo, nodeInfoResponse.verified())
|
||||
|
||||
assertThatExceptionOfType(FileNotFoundException::class.java).isThrownBy {
|
||||
it.doGet<SignedNodeInfo>("node-info/${randomSHA256()}")
|
||||
}
|
||||
assertThatExceptionOfType(IOException::class.java)
|
||||
.isThrownBy { it.doGet<SignedNodeInfo>("node-info/${randomSHA256()}") }
|
||||
.withMessageContaining("404")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get network parameters`() {
|
||||
val netParams = testNetworkParameters(emptyList())
|
||||
val serializedNetParams = netParams.serialize()
|
||||
val signedNetParams = SignedData(serializedNetParams, intermediateCa.keyPair.sign(serializedNetParams))
|
||||
val netParamsHash = serializedNetParams.hash
|
||||
val networkParameters = testNetworkParameters(emptyList())
|
||||
val signedNetworkParameters = networkParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)
|
||||
val networkParametersHash = signedNetworkParameters.raw.hash
|
||||
|
||||
val networkMapStorage: NetworkMapStorage = mock {
|
||||
on { getSignedNetworkParameters(netParamsHash) }.thenReturn(signedNetParams)
|
||||
on { getSignedNetworkParameters(networkParametersHash) }.thenReturn(signedNetworkParameters)
|
||||
}
|
||||
|
||||
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(mock(), networkMapStorage, testNetworkMapConfig)).use {
|
||||
it.start()
|
||||
val netParamsResponse = it.doGet<SignedData<NetworkParameters>>("network-parameter/$netParamsHash")
|
||||
verify(networkMapStorage, times(1)).getSignedNetworkParameters(netParamsHash)
|
||||
assertThat(netParamsResponse.verified()).isEqualTo(netParams)
|
||||
assertThat(netParamsResponse.sig.by).isEqualTo(intermediateCa.keyPair.public)
|
||||
val netParamsResponse = it.doGet<SignedNetworkParameters>("network-parameters/$networkParametersHash")
|
||||
verify(networkMapStorage, times(1)).getSignedNetworkParameters(networkParametersHash)
|
||||
assertThat(netParamsResponse.verified()).isEqualTo(networkParameters)
|
||||
assertThat(netParamsResponse.sig.by).isEqualTo(networkMapCa.certificate)
|
||||
|
||||
assertThatExceptionOfType(FileNotFoundException::class.java).isThrownBy {
|
||||
it.doGet<SignedData<NetworkParameters>>("network-parameter/${randomSHA256()}")
|
||||
}
|
||||
assertThatExceptionOfType(IOException::class.java)
|
||||
.isThrownBy { it.doGet<SignedNetworkParameters>("network-parameters/${randomSHA256()}") }
|
||||
.withMessageContaining("404")
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,15 +169,11 @@ class NodeInfoWebServiceTest {
|
||||
requestMethod = "POST"
|
||||
setRequestProperty("Content-Type", MediaType.APPLICATION_OCTET_STREAM)
|
||||
outputStream.write(payload)
|
||||
if (responseCode != 200) {
|
||||
throw IOException("Response Code $responseCode: ${IOUtils.toString(errorStream, Charset.defaultCharset())}")
|
||||
}
|
||||
inputStream.close()
|
||||
checkOkResponse()
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified T : Any> NetworkManagementWebServer.doGet(path: String): T {
|
||||
val url = URL("http://$hostAndPort/network-map/$path")
|
||||
return url.openHttpConnection().inputStream.use { it.readBytes().deserialize() }
|
||||
return URL("http://$hostAndPort/network-map/$path").openHttpConnection().responseAs()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user