mirror of
https://github.com/corda/corda.git
synced 2025-06-18 07:08:15 +00:00
Adding sockets (#570)
* Adding sockets * Addressing review comments * Adding review comments * Addressing review comments
This commit is contained in:
@ -4,7 +4,7 @@ keySpecifier = -1
|
|||||||
|
|
||||||
doorman {
|
doorman {
|
||||||
crlDistributionPoint = "http://test.com/revoked.crl"
|
crlDistributionPoint = "http://test.com/revoked.crl"
|
||||||
compatibilityZoneURL = "http://test.com/api"
|
crlServerSocketAddress = "test.com:2333"
|
||||||
crlUpdatePeriod = 200000
|
crlUpdatePeriod = 200000
|
||||||
validDays = 3650
|
validDays = 3650
|
||||||
rootKeyStoreFile = "dummyfile.jks"
|
rootKeyStoreFile = "dummyfile.jks"
|
||||||
|
@ -24,6 +24,7 @@ import com.r3.corda.networkmanage.hsm.generator.GeneratorParameters
|
|||||||
import com.r3.corda.networkmanage.hsm.generator.UserAuthenticationParameters
|
import com.r3.corda.networkmanage.hsm.generator.UserAuthenticationParameters
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
@ -146,7 +147,7 @@ abstract class HsmBaseTest {
|
|||||||
validDays = 3650,
|
validDays = 3650,
|
||||||
rootKeyStorePassword = TRUSTSTORE_PASSWORD,
|
rootKeyStorePassword = TRUSTSTORE_PASSWORD,
|
||||||
crlDistributionPoint = URL("http://test.com/revoked.crl"),
|
crlDistributionPoint = URL("http://test.com/revoked.crl"),
|
||||||
compatibilityZoneURL = URL("http://test.com/api"),
|
crlServerSocketAddress = NetworkHostAndPort("test.com", 4555),
|
||||||
crlUpdatePeriod = 1000,
|
crlUpdatePeriod = 1000,
|
||||||
authParameters = AuthParametersConfig(
|
authParameters = AuthParametersConfig(
|
||||||
mode = SigningServiceAuthMode.PASSWORD,
|
mode = SigningServiceAuthMode.PASSWORD,
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.r3.corda.networkmanage.common.sockets
|
||||||
|
|
||||||
|
import net.corda.core.serialization.CordaSerializable
|
||||||
|
import java.security.cert.X509CRL
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
@CordaSerializable
|
||||||
|
data class CertificateRevocationListSubmission(val list: X509CRL,
|
||||||
|
val signer: String,
|
||||||
|
val revocationTime: Instant)
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.r3.corda.networkmanage.common.sockets
|
||||||
|
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.RequestStatus
|
||||||
|
import net.corda.core.serialization.CordaSerializable
|
||||||
|
import java.security.cert.X509CRL
|
||||||
|
|
||||||
|
@CordaSerializable
|
||||||
|
interface CrrSocketMessage
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CRL retrieval message type
|
||||||
|
*/
|
||||||
|
class CrlRetrievalMessage : CrrSocketMessage
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CRL response message type
|
||||||
|
*/
|
||||||
|
data class CrlResponseMessage(val crl: X509CRL?) : CrrSocketMessage
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CRL submission message type
|
||||||
|
*/
|
||||||
|
class CrlSubmissionMessage : CrrSocketMessage
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By status CRRs retrieval message type
|
||||||
|
*/
|
||||||
|
data class CrrsByStatusMessage(val status: RequestStatus) : CrrSocketMessage
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.r3.corda.networkmanage.common.utils
|
||||||
|
|
||||||
|
import net.corda.core.serialization.deserialize
|
||||||
|
import net.corda.core.serialization.serialize
|
||||||
|
import java.io.DataInputStream
|
||||||
|
import java.io.DataOutputStream
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
|
||||||
|
inline fun <reified T : Any> InputStream.readObject(): T {
|
||||||
|
DataInputStream(this).run {
|
||||||
|
val messageSize = this.readInt()
|
||||||
|
val messageBytes = ByteArray(messageSize)
|
||||||
|
this.read(messageBytes)
|
||||||
|
return messageBytes.deserialize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun OutputStream.writeObject(message: Any) {
|
||||||
|
DataOutputStream(this).run {
|
||||||
|
val messageBytes = message.serialize().bytes
|
||||||
|
this.writeInt(messageBytes.size)
|
||||||
|
this.write(messageBytes)
|
||||||
|
this.flush()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
package com.r3.corda.networkmanage.doorman.sockets
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors.shutdownAndAwaitTermination
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.CertificateRevocationListStorage
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.CertificateRevocationRequestStorage
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.CrlIssuer
|
||||||
|
import com.r3.corda.networkmanage.common.sockets.*
|
||||||
|
import com.r3.corda.networkmanage.common.utils.readObject
|
||||||
|
import com.r3.corda.networkmanage.common.utils.writeObject
|
||||||
|
import net.corda.core.utilities.contextLogger
|
||||||
|
import net.corda.core.utilities.seconds
|
||||||
|
import java.net.ServerSocket
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class CertificateRevocationSocketServer(val port: Int,
|
||||||
|
private val crlStorage: CertificateRevocationListStorage,
|
||||||
|
private val crrStorage: CertificateRevocationRequestStorage) : AutoCloseable {
|
||||||
|
private companion object {
|
||||||
|
private val logger = contextLogger()
|
||||||
|
|
||||||
|
private val RECONNECT_INTERVAL = 10.seconds.toMillis()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val executor = Executors.newSingleThreadScheduledExecutor()
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
private var isRunning = false
|
||||||
|
|
||||||
|
fun start() {
|
||||||
|
check(!isRunning) { "The server has already been started." }
|
||||||
|
isRunning = true
|
||||||
|
executor.submit {
|
||||||
|
while (isRunning) {
|
||||||
|
try {
|
||||||
|
listen()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error("Socket execution error.", e)
|
||||||
|
if (isRunning) {
|
||||||
|
logger.info("Server socket will be recreated in $RECONNECT_INTERVAL milliseconds")
|
||||||
|
Thread.sleep(RECONNECT_INTERVAL)
|
||||||
|
logger.info("Recreating server socket...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
isRunning = false
|
||||||
|
shutdownAndAwaitTermination(executor, RECONNECT_INTERVAL, TimeUnit.MILLISECONDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun listen() {
|
||||||
|
ServerSocket(port).use {
|
||||||
|
logger.info("Server socket is running.")
|
||||||
|
while (isRunning) {
|
||||||
|
logger.debug("Waiting for socket data...")
|
||||||
|
val acceptedSocket = it.accept()
|
||||||
|
acceptedSocket.use {
|
||||||
|
val message = it.getInputStream().readObject<CrrSocketMessage>()
|
||||||
|
logger.debug("Received message type is $message.")
|
||||||
|
acceptedSocket.getOutputStream().let {
|
||||||
|
when (message) {
|
||||||
|
is CrlRetrievalMessage -> {
|
||||||
|
val crl = crlStorage.getCertificateRevocationList(CrlIssuer.DOORMAN)
|
||||||
|
it.writeObject(CrlResponseMessage(crl))
|
||||||
|
logger.debug("Sending the current certificate revocation list.")
|
||||||
|
}
|
||||||
|
is CrrsByStatusMessage -> {
|
||||||
|
it.writeObject(crrStorage.getRevocationRequests(message.status))
|
||||||
|
logger.debug("Sending ${message.status.name} certificate revocation requests.")
|
||||||
|
}
|
||||||
|
is CrlSubmissionMessage -> {
|
||||||
|
val crlSubmission = acceptedSocket.getInputStream().readObject<CertificateRevocationListSubmission>()
|
||||||
|
crlStorage.saveCertificateRevocationList(crlSubmission.list, CrlIssuer.DOORMAN, crlSubmission.signer, crlSubmission.revocationTime)
|
||||||
|
}
|
||||||
|
else -> logger.warn("Unknown message type $message")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -6,7 +6,6 @@ import com.r3.corda.networkmanage.common.persistence.CertificateRevocationListSt
|
|||||||
import com.r3.corda.networkmanage.common.persistence.CrlIssuer
|
import com.r3.corda.networkmanage.common.persistence.CrlIssuer
|
||||||
import com.r3.corda.networkmanage.doorman.webservice.CertificateRevocationListWebService.Companion.CRL_PATH
|
import com.r3.corda.networkmanage.doorman.webservice.CertificateRevocationListWebService.Companion.CRL_PATH
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import java.util.concurrent.ExecutionException
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.ws.rs.GET
|
import javax.ws.rs.GET
|
||||||
import javax.ws.rs.Path
|
import javax.ws.rs.Path
|
||||||
|
@ -62,6 +62,6 @@ fun main(args: Array<String>) {
|
|||||||
} else if (config.doorman != null) {
|
} else if (config.doorman != null) {
|
||||||
CsrProcessor(config.doorman, config.device, config.keySpecifier, persistence).showMenu()
|
CsrProcessor(config.doorman, config.device, config.keySpecifier, persistence).showMenu()
|
||||||
} else if (config.doorman != null) {
|
} else if (config.doorman != null) {
|
||||||
CrrProcessor(config.doorman, config.device, config.keySpecifier, persistence).showMenu()
|
CrrProcessor(config.doorman, config.device, config.keySpecifier).showMenu()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,11 @@ import joptsimple.OptionParser
|
|||||||
import joptsimple.util.PathConverter
|
import joptsimple.util.PathConverter
|
||||||
import joptsimple.util.PathProperties
|
import joptsimple.util.PathProperties
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.nodeapi.internal.config.parseAs
|
import net.corda.nodeapi.internal.config.parseAs
|
||||||
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
||||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||||
|
import java.net.InetAddress
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
@ -56,7 +58,7 @@ data class NetworkMapCertificateConfig(val username: String,
|
|||||||
* Certificate signing requests process specific parameters.
|
* Certificate signing requests process specific parameters.
|
||||||
*/
|
*/
|
||||||
data class DoormanCertificateConfig(val crlDistributionPoint: URL,
|
data class DoormanCertificateConfig(val crlDistributionPoint: URL,
|
||||||
val compatibilityZoneURL: URL,
|
val crlServerSocketAddress: NetworkHostAndPort,
|
||||||
val crlUpdatePeriod: Long,
|
val crlUpdatePeriod: Long,
|
||||||
val keyGroup:String,
|
val keyGroup:String,
|
||||||
val validDays: Int,
|
val validDays: Int,
|
||||||
|
@ -1,26 +1,22 @@
|
|||||||
package com.r3.corda.networkmanage.hsm.processor
|
package com.r3.corda.networkmanage.hsm.processor
|
||||||
|
|
||||||
import com.google.common.net.HostAndPort
|
|
||||||
import com.r3.corda.networkmanage.common.persistence.CrlIssuer
|
import com.r3.corda.networkmanage.common.persistence.CrlIssuer
|
||||||
import com.r3.corda.networkmanage.common.persistence.PersistentCertificateRevocationListStorage
|
|
||||||
import com.r3.corda.networkmanage.common.persistence.PersistentCertificateRevocationRequestStorage
|
|
||||||
import com.r3.corda.networkmanage.common.persistence.RequestStatus
|
|
||||||
import com.r3.corda.networkmanage.common.signer.CertificateRevocationListSigner
|
import com.r3.corda.networkmanage.common.signer.CertificateRevocationListSigner
|
||||||
import com.r3.corda.networkmanage.hsm.authentication.Authenticator
|
import com.r3.corda.networkmanage.hsm.authentication.Authenticator
|
||||||
import com.r3.corda.networkmanage.hsm.authentication.createProvider
|
import com.r3.corda.networkmanage.hsm.authentication.createProvider
|
||||||
import com.r3.corda.networkmanage.hsm.configuration.DoormanCertificateConfig
|
import com.r3.corda.networkmanage.hsm.configuration.DoormanCertificateConfig
|
||||||
import com.r3.corda.networkmanage.hsm.menu.Menu
|
import com.r3.corda.networkmanage.hsm.menu.Menu
|
||||||
import com.r3.corda.networkmanage.hsm.signer.HsmSigner
|
import com.r3.corda.networkmanage.hsm.signer.HsmSigner
|
||||||
|
import com.r3.corda.networkmanage.hsm.sockets.SocketCertificateRevocationList
|
||||||
|
import com.r3.corda.networkmanage.hsm.sockets.CertificateRevocationRequestRetriever
|
||||||
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.getAndInitializeKeyStore
|
import com.r3.corda.networkmanage.hsm.utils.HsmX509Utilities.getAndInitializeKeyStore
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_INTERMEDIATE_CA
|
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_INTERMEDIATE_CA
|
||||||
import net.corda.nodeapi.internal.crypto.getX509Certificate
|
import net.corda.nodeapi.internal.crypto.getX509Certificate
|
||||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
|
||||||
class CrrProcessor(private val config: DoormanCertificateConfig,
|
class CrrProcessor(private val config: DoormanCertificateConfig,
|
||||||
private val device: String,
|
private val device: String,
|
||||||
private val keySpecifier: Int,
|
private val keySpecifier: Int) : Processor() {
|
||||||
private val persistance: CordaPersistence) : Processor() {
|
|
||||||
private companion object {
|
private companion object {
|
||||||
private const val RESET = "\u001B[0m"
|
private const val RESET = "\u001B[0m"
|
||||||
private const val BLACK = "\u001B[30m"
|
private const val BLACK = "\u001B[30m"
|
||||||
@ -40,12 +36,12 @@ class CrrProcessor(private val config: DoormanCertificateConfig,
|
|||||||
mode = auth.mode,
|
mode = auth.mode,
|
||||||
authStrengthThreshold = auth.threshold)
|
authStrengthThreshold = auth.threshold)
|
||||||
Menu().withExceptionHandler(this::processError).setExitOption("2", "Quit").addItem("1", "View current and sign a new certificate revocation list", {
|
Menu().withExceptionHandler(this::processError).setExitOption("2", "Quit").addItem("1", "View current and sign a new certificate revocation list", {
|
||||||
val crlStorage = PersistentCertificateRevocationListStorage(persistance)
|
val crlTransceiver = SocketCertificateRevocationList(config.crlServerSocketAddress)
|
||||||
val currentCrl = crlStorage.getCertificateRevocationList(CrlIssuer.DOORMAN)
|
val currentCrl = crlTransceiver.getCertificateRevocationList(CrlIssuer.DOORMAN)
|
||||||
printlnColor("Current CRL:")
|
printlnColor("Current CRL:")
|
||||||
printlnColor(currentCrl.toString(), YELLOW)
|
printlnColor(currentCrl.toString(), YELLOW)
|
||||||
val crrStorage = PersistentCertificateRevocationRequestStorage(persistance)
|
val crrRetriever = CertificateRevocationRequestRetriever(config.crlServerSocketAddress)
|
||||||
val approvedRequests = crrStorage.getRevocationRequests(RequestStatus.APPROVED)
|
val approvedRequests = crrRetriever.retrieveApprovedCertificateRevocationRequests()
|
||||||
if (approvedRequests.isEmpty()) {
|
if (approvedRequests.isEmpty()) {
|
||||||
printlnColor("There are no approved Certificate Revocation Requests.", GREEN)
|
printlnColor("There are no approved Certificate Revocation Requests.", GREEN)
|
||||||
} else {
|
} else {
|
||||||
@ -60,12 +56,12 @@ class CrrProcessor(private val config: DoormanCertificateConfig,
|
|||||||
val keyStore = getAndInitializeKeyStore(provider)
|
val keyStore = getAndInitializeKeyStore(provider)
|
||||||
val issuerCertificate = keyStore.getX509Certificate(CORDA_INTERMEDIATE_CA)
|
val issuerCertificate = keyStore.getX509Certificate(CORDA_INTERMEDIATE_CA)
|
||||||
val crlSigner = CertificateRevocationListSigner(
|
val crlSigner = CertificateRevocationListSigner(
|
||||||
revocationListStorage = crlStorage,
|
revocationListStorage = crlTransceiver,
|
||||||
issuerCertificate = issuerCertificate,
|
issuerCertificate = issuerCertificate,
|
||||||
updateInterval = Duration.ofMillis(config.crlUpdatePeriod),
|
updateInterval = Duration.ofMillis(config.crlUpdatePeriod),
|
||||||
endpoint = config.crlDistributionPoint,
|
endpoint = config.crlDistributionPoint,
|
||||||
signer = HsmSigner(provider = provider, keyName = CORDA_INTERMEDIATE_CA))
|
signer = HsmSigner(provider = provider, keyName = CORDA_INTERMEDIATE_CA))
|
||||||
val currentRequests = crrStorage.getRevocationRequests(RequestStatus.DONE)
|
val currentRequests = crrRetriever.retrieveDoneCertificateRevocationRequests()
|
||||||
crlSigner.createSignedCRL(approvedRequests, currentRequests, signers.toString())
|
crlSigner.createSignedCRL(approvedRequests, currentRequests, signers.toString())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
package com.r3.corda.networkmanage.hsm.sockets
|
||||||
|
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.CertificateRevocationRequestData
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.RequestStatus
|
||||||
|
import com.r3.corda.networkmanage.common.sockets.CrrsByStatusMessage
|
||||||
|
import com.r3.corda.networkmanage.common.utils.readObject
|
||||||
|
import com.r3.corda.networkmanage.common.utils.writeObject
|
||||||
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
|
import net.corda.core.utilities.contextLogger
|
||||||
|
import java.net.Socket
|
||||||
|
|
||||||
|
class CertificateRevocationRequestRetriever(private val serverHostAndPort: NetworkHostAndPort) {
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
private val logger = contextLogger()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun retrieveApprovedCertificateRevocationRequests(): List<CertificateRevocationRequestData> {
|
||||||
|
return retrieveCertificateRevocationRequests(RequestStatus.APPROVED)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun retrieveDoneCertificateRevocationRequests(): List<CertificateRevocationRequestData> {
|
||||||
|
return retrieveCertificateRevocationRequests(RequestStatus.DONE)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun retrieveCertificateRevocationRequests(status: RequestStatus): List<CertificateRevocationRequestData> {
|
||||||
|
require(status == RequestStatus.DONE || status == RequestStatus.APPROVED) { "Allowed status values: APPROVED, DONE" }
|
||||||
|
return Socket(serverHostAndPort.host, serverHostAndPort.port).use {
|
||||||
|
it.getOutputStream().let {
|
||||||
|
logger.debug("Requesting $status certificate revocation requests...")
|
||||||
|
it.writeObject(CrrsByStatusMessage(status))
|
||||||
|
}
|
||||||
|
it.getInputStream().readObject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.r3.corda.networkmanage.hsm.sockets
|
||||||
|
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.CertificateRevocationListStorage
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.CrlIssuer
|
||||||
|
import com.r3.corda.networkmanage.common.sockets.CertificateRevocationListSubmission
|
||||||
|
import com.r3.corda.networkmanage.common.sockets.CrlResponseMessage
|
||||||
|
import com.r3.corda.networkmanage.common.sockets.CrlRetrievalMessage
|
||||||
|
import com.r3.corda.networkmanage.common.sockets.CrlSubmissionMessage
|
||||||
|
import com.r3.corda.networkmanage.common.utils.readObject
|
||||||
|
import com.r3.corda.networkmanage.common.utils.writeObject
|
||||||
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
|
import net.corda.core.utilities.contextLogger
|
||||||
|
import java.net.Socket
|
||||||
|
import java.security.cert.X509CRL
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
class SocketCertificateRevocationList(private val serverHostAndPort: NetworkHostAndPort) : CertificateRevocationListStorage {
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
private val logger = contextLogger()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCertificateRevocationList(crlIssuer: CrlIssuer): X509CRL? {
|
||||||
|
return Socket(serverHostAndPort.host, serverHostAndPort.port).use {
|
||||||
|
logger.debug("Requesting the current revocation list...")
|
||||||
|
it.getOutputStream().writeObject(CrlRetrievalMessage())
|
||||||
|
it.getInputStream().readObject<CrlResponseMessage>().crl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun saveCertificateRevocationList(crl: X509CRL, crlIssuer: CrlIssuer, signedBy: String, revokedAt: Instant) {
|
||||||
|
Socket(serverHostAndPort.host, serverHostAndPort.port).use {
|
||||||
|
it.getOutputStream().let {
|
||||||
|
it.writeObject(CrlSubmissionMessage())
|
||||||
|
logger.debug("Submitting a new revocation list...")
|
||||||
|
it.writeObject(CertificateRevocationListSubmission(crl, signedBy, revokedAt))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,123 @@
|
|||||||
|
package com.r3.corda.networkmanage.doorman.sockets
|
||||||
|
|
||||||
|
import com.nhaarman.mockito_kotlin.eq
|
||||||
|
import com.nhaarman.mockito_kotlin.mock
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.*
|
||||||
|
import com.r3.corda.networkmanage.common.sockets.CrlResponseMessage
|
||||||
|
import com.r3.corda.networkmanage.common.sockets.CrlRetrievalMessage
|
||||||
|
import com.r3.corda.networkmanage.common.sockets.CrrsByStatusMessage
|
||||||
|
import com.r3.corda.networkmanage.common.utils.readObject
|
||||||
|
import com.r3.corda.networkmanage.common.utils.writeObject
|
||||||
|
import net.corda.core.crypto.Crypto
|
||||||
|
import net.corda.core.identity.CordaX500Name
|
||||||
|
import net.corda.core.internal.x500Name
|
||||||
|
import net.corda.nodeapi.internal.crypto.ContentSignerBuilder
|
||||||
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
|
import net.corda.testing.core.freePort
|
||||||
|
import net.corda.testing.internal.DEV_INTERMEDIATE_CA
|
||||||
|
import org.bouncycastle.cert.X509v2CRLBuilder
|
||||||
|
import org.bouncycastle.cert.jcajce.JcaX509CRLConverter
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.net.Socket
|
||||||
|
import java.security.cert.CRLReason
|
||||||
|
import java.security.cert.X509CRL
|
||||||
|
import java.time.Instant
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
|
||||||
|
class CertificateRevocationSocketServerTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
@JvmField
|
||||||
|
val testSerialization = SerializationEnvironmentRule(true)
|
||||||
|
|
||||||
|
private lateinit var crlStorage: CertificateRevocationListStorage
|
||||||
|
private lateinit var crrStorage: CertificateRevocationRequestStorage
|
||||||
|
private lateinit var server: CertificateRevocationSocketServer
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
crlStorage = mock {
|
||||||
|
on { getCertificateRevocationList(eq(CrlIssuer.DOORMAN)) }.then { createCrl() }
|
||||||
|
}
|
||||||
|
crrStorage = mock {
|
||||||
|
on { getRevocationRequests(eq(RequestStatus.APPROVED)) }.then { listOf(createCertificateRevocationRequest(RequestStatus.APPROVED)) }
|
||||||
|
on { getRevocationRequests(eq(RequestStatus.DONE)) }.then { listOf(createCertificateRevocationRequest(RequestStatus.DONE)) }
|
||||||
|
}
|
||||||
|
server = CertificateRevocationSocketServer(freePort(), crlStorage, crrStorage)
|
||||||
|
server.start()
|
||||||
|
Thread.sleep(100)
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
server.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `crl is served correctly`() {
|
||||||
|
// given
|
||||||
|
|
||||||
|
// when
|
||||||
|
val crl = Socket("localhost", server.port).use {
|
||||||
|
it.getOutputStream().writeObject(CrlRetrievalMessage())
|
||||||
|
it.getInputStream().readObject<CrlResponseMessage>().crl
|
||||||
|
}
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertNotNull(crl)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `approved requests are served correctly`() {
|
||||||
|
// given
|
||||||
|
|
||||||
|
// when
|
||||||
|
val approvedRequests = Socket("localhost", server.port).use {
|
||||||
|
it.getOutputStream().writeObject(CrrsByStatusMessage(RequestStatus.APPROVED))
|
||||||
|
it.getInputStream().readObject<List<CertificateRevocationRequestData>>()
|
||||||
|
}
|
||||||
|
// then
|
||||||
|
assertNotNull(approvedRequests)
|
||||||
|
assertEquals(RequestStatus.APPROVED, approvedRequests.first().status)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `done requests are served correctly`() {
|
||||||
|
// given
|
||||||
|
|
||||||
|
// when
|
||||||
|
val doneRequests = Socket("localhost", server.port).use {
|
||||||
|
it.getOutputStream().writeObject(CrrsByStatusMessage(RequestStatus.DONE))
|
||||||
|
it.getInputStream().readObject<List<CertificateRevocationRequestData>>()
|
||||||
|
}
|
||||||
|
// then
|
||||||
|
assertNotNull(doneRequests)
|
||||||
|
assertEquals(RequestStatus.DONE, doneRequests.first().status)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCrl(): X509CRL {
|
||||||
|
val builder = X509v2CRLBuilder(CordaX500Name.build(DEV_INTERMEDIATE_CA.certificate.issuerX500Principal).x500Name, Date())
|
||||||
|
val provider = BouncyCastleProvider()
|
||||||
|
val crlHolder = builder.build(ContentSignerBuilder.build(Crypto.RSA_SHA256, Crypto.generateKeyPair(Crypto.RSA_SHA256).private, provider))
|
||||||
|
return JcaX509CRLConverter().setProvider(provider).getCRL(crlHolder)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCertificateRevocationRequest(status: RequestStatus): CertificateRevocationRequestData {
|
||||||
|
return CertificateRevocationRequestData(
|
||||||
|
requestId = "123",
|
||||||
|
legalName = CordaX500Name.parse("CN=Test Corp, O=Test, L=London, C=GB"),
|
||||||
|
reporter = "Test",
|
||||||
|
certificateSerialNumber = BigInteger.TEN,
|
||||||
|
status = status,
|
||||||
|
reason = CRLReason.KEY_COMPROMISE,
|
||||||
|
modifiedAt = Instant.now()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* R3 Proprietary and Confidential
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 R3 Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
|
||||||
|
*
|
||||||
|
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
|
||||||
|
*/
|
||||||
|
|
||||||
package net.corda.nodeapi.internal.serialization.amqp.custom
|
package net.corda.nodeapi.internal.serialization.amqp.custom
|
||||||
|
|
||||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||||
|
Reference in New Issue
Block a user