mirror of
https://github.com/corda/corda.git
synced 2024-12-31 18:27:05 +00:00
Tidy up based upon comments on PR
This commit is contained in:
parent
196fe57147
commit
b042fac905
@ -55,7 +55,7 @@ object X509Utilities {
|
|||||||
* @param parentNotBefore if provided is used to lower bound the date interval returned
|
* @param parentNotBefore if provided is used to lower bound the date interval returned
|
||||||
* @param parentNotAfter if provided is used to upper bound the date interval returned
|
* @param parentNotAfter if provided is used to upper bound the date interval returned
|
||||||
*/
|
*/
|
||||||
private fun GetCertificateValidityWindow(daysBefore: Int, daysAfter: Int, parentNotBefore: Date? = null, parentNotAfter: Date? = null): Pair<Date, Date> {
|
private fun getCertificateValidityWindow(daysBefore: Int, daysAfter: Int, parentNotBefore: Date? = null, parentNotAfter: Date? = null): Pair<Date, Date> {
|
||||||
val startOfDayUTC = Instant.now().truncatedTo(ChronoUnit.DAYS)
|
val startOfDayUTC = Instant.now().truncatedTo(ChronoUnit.DAYS)
|
||||||
|
|
||||||
var notBefore = Date.from(startOfDayUTC.minus(daysBefore.toLong(), ChronoUnit.DAYS))
|
var notBefore = Date.from(startOfDayUTC.minus(daysBefore.toLong(), ChronoUnit.DAYS))
|
||||||
@ -94,7 +94,7 @@ object X509Utilities {
|
|||||||
/**
|
/**
|
||||||
* Helper method to create Subject field contents
|
* Helper method to create Subject field contents
|
||||||
*/
|
*/
|
||||||
fun GetX509Name(domain: String): X500Name {
|
fun getDevX509Name(domain: String): X500Name {
|
||||||
val nameBuilder = X500NameBuilder(BCStyle.INSTANCE)
|
val nameBuilder = X500NameBuilder(BCStyle.INSTANCE)
|
||||||
nameBuilder.addRDN(BCStyle.CN, domain)
|
nameBuilder.addRDN(BCStyle.CN, domain)
|
||||||
nameBuilder.addRDN(BCStyle.O, "R3")
|
nameBuilder.addRDN(BCStyle.O, "R3")
|
||||||
@ -121,6 +121,10 @@ object X509Utilities {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
keyStore.load(null, pass)
|
keyStore.load(null, pass)
|
||||||
|
val output = FileOutputStream(keyStoreFilePath.toFile())
|
||||||
|
output.use {
|
||||||
|
keyStore.store(output, pass)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return keyStore
|
return keyStore
|
||||||
}
|
}
|
||||||
@ -231,11 +235,14 @@ object X509Utilities {
|
|||||||
fun createSelfSignedCACert(domain: String): CACertAndKey {
|
fun createSelfSignedCACert(domain: String): CACertAndKey {
|
||||||
val keyPair = generateECDSAKeyPairForSSL()
|
val keyPair = generateECDSAKeyPairForSSL()
|
||||||
|
|
||||||
val issuer = GetX509Name(domain)
|
val issuer = getDevX509Name(domain)
|
||||||
val serial = BigInteger.valueOf(random63BitValue())
|
val serial = BigInteger.valueOf(random63BitValue())
|
||||||
val subject = issuer
|
val subject = issuer
|
||||||
val pubKey = keyPair.public
|
val pubKey = keyPair.public
|
||||||
val window = GetCertificateValidityWindow(0, 365 * 10)
|
|
||||||
|
// Ten year certificate validity
|
||||||
|
// TODO how do we manage certificate expiry, revocation and loss
|
||||||
|
val window = getCertificateValidityWindow(0, 365 * 10)
|
||||||
|
|
||||||
val builder = JcaX509v3CertificateBuilder(
|
val builder = JcaX509v3CertificateBuilder(
|
||||||
issuer, serial, window.first, window.second, subject, pubKey)
|
issuer, serial, window.first, window.second, subject, pubKey)
|
||||||
@ -276,10 +283,12 @@ object X509Utilities {
|
|||||||
|
|
||||||
val issuer = X509CertificateHolder(certificateAuthority.certificate.encoded).subject
|
val issuer = X509CertificateHolder(certificateAuthority.certificate.encoded).subject
|
||||||
val serial = BigInteger.valueOf(random63BitValue())
|
val serial = BigInteger.valueOf(random63BitValue())
|
||||||
val subject = GetX509Name(domain)
|
val subject = getDevX509Name(domain)
|
||||||
val pubKey = keyPair.public
|
val pubKey = keyPair.public
|
||||||
// One year certificate validity
|
|
||||||
val window = GetCertificateValidityWindow(0, 365, certificateAuthority.certificate.notBefore, certificateAuthority.certificate.notAfter)
|
// Ten year certificate validity
|
||||||
|
// TODO how do we manage certificate expiry, revocation and loss
|
||||||
|
val window = getCertificateValidityWindow(0, 365*10, certificateAuthority.certificate.notBefore, certificateAuthority.certificate.notAfter)
|
||||||
|
|
||||||
val builder = JcaX509v3CertificateBuilder(
|
val builder = JcaX509v3CertificateBuilder(
|
||||||
issuer, serial, window.first, window.second, subject, pubKey)
|
issuer, serial, window.first, window.second, subject, pubKey)
|
||||||
@ -325,7 +334,10 @@ object X509Utilities {
|
|||||||
|
|
||||||
val issuer = X509CertificateHolder(certificateAuthority.certificate.encoded).subject
|
val issuer = X509CertificateHolder(certificateAuthority.certificate.encoded).subject
|
||||||
val serial = BigInteger.valueOf(random63BitValue())
|
val serial = BigInteger.valueOf(random63BitValue())
|
||||||
val window = GetCertificateValidityWindow(0, 365, certificateAuthority.certificate.notBefore, certificateAuthority.certificate.notAfter)
|
|
||||||
|
// Ten year certificate validity
|
||||||
|
// TODO how do we manage certificate expiry, revocation and loss
|
||||||
|
val window = getCertificateValidityWindow(0, 365*10, certificateAuthority.certificate.notBefore, certificateAuthority.certificate.notAfter)
|
||||||
|
|
||||||
val builder = JcaX509v3CertificateBuilder(issuer, serial, window.first, window.second, subject, publicKey)
|
val builder = JcaX509v3CertificateBuilder(issuer, serial, window.first, window.second, subject, publicKey)
|
||||||
builder.addExtension(Extension.subjectKeyIdentifier, false, createSubjectKeyIdentifier(publicKey))
|
builder.addExtension(Extension.subjectKeyIdentifier, false, createSubjectKeyIdentifier(publicKey))
|
||||||
@ -518,7 +530,7 @@ object X509Utilities {
|
|||||||
|
|
||||||
val serverKey = X509Utilities.generateECDSAKeyPairForSSL()
|
val serverKey = X509Utilities.generateECDSAKeyPairForSSL()
|
||||||
val host = InetAddress.getLocalHost()
|
val host = InetAddress.getLocalHost()
|
||||||
val subject = GetX509Name(host.canonicalHostName)
|
val subject = getDevX509Name(host.canonicalHostName)
|
||||||
val serverCert = X509Utilities.createServerCert(subject,
|
val serverCert = X509Utilities.createServerCert(subject,
|
||||||
serverKey.public,
|
serverKey.public,
|
||||||
intermediateCA,
|
intermediateCA,
|
||||||
|
@ -54,7 +54,7 @@ class X509UtilitiesTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `create valid server certificate chain`() {
|
fun `create valid server certificate chain`() {
|
||||||
val caCertAndKey = X509Utilities.createSelfSignedCACert("Test CA Cert")
|
val caCertAndKey = X509Utilities.createSelfSignedCACert("Test CA Cert")
|
||||||
val subjectDN = X509Utilities.GetX509Name("Server Cert")
|
val subjectDN = X509Utilities.getDevX509Name("Server Cert")
|
||||||
val keypair = X509Utilities.generateECDSAKeyPairForSSL()
|
val keypair = X509Utilities.generateECDSAKeyPairForSSL()
|
||||||
val serverCert = X509Utilities.createServerCert(subjectDN, keypair.public, caCertAndKey, listOf("alias name"), listOf("10.0.0.54"))
|
val serverCert = X509Utilities.createServerCert(subjectDN, keypair.public, caCertAndKey, listOf("alias name"), listOf("10.0.0.54"))
|
||||||
assertTrue { serverCert.subjectDN.name.contains("CN=Server Cert") } // using our subject common name
|
assertTrue { serverCert.subjectDN.name.contains("CN=Server Cert") } // using our subject common name
|
||||||
|
@ -72,7 +72,7 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort,
|
|||||||
override fun startMessagingService() {
|
override fun startMessagingService() {
|
||||||
// Start up the MQ service.
|
// Start up the MQ service.
|
||||||
(net as ArtemisMessagingService).apply {
|
(net as ArtemisMessagingService).apply {
|
||||||
configureWithDevSSLCertificate() //Provision a dev certificate and private key if required
|
configureWithDevSSLCertificate() // TODO Create proper certificate provisioning process
|
||||||
start()
|
start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ import javax.annotation.concurrent.ThreadSafe
|
|||||||
/**
|
/**
|
||||||
* This class implements the [MessagingService] API using Apache Artemis, the successor to their ActiveMQ product.
|
* This class implements the [MessagingService] API using Apache Artemis, the successor to their ActiveMQ product.
|
||||||
* Artemis is a message queue broker and here, we embed the entire server inside our own process. Nodes communicate
|
* Artemis is a message queue broker and here, we embed the entire server inside our own process. Nodes communicate
|
||||||
* with each other using an Artemis specific protocol, but it supports other protocols like AQMP/1.0
|
* with each other using an Artemis specific protocol, but it supports other protocols like AMQP/1.0
|
||||||
* as well for interop.
|
* as well for interop.
|
||||||
*
|
*
|
||||||
* The current implementation is skeletal and lacks features like security or firewall tunnelling (that is, you must
|
* The current implementation is skeletal and lacks features like security or firewall tunnelling (that is, you must
|
||||||
@ -99,6 +99,14 @@ class ArtemisMessagingService(val directory: Path,
|
|||||||
private val keyStorePath = directory.resolve("certificates").resolve("sslkeystore.jks")
|
private val keyStorePath = directory.resolve("certificates").resolve("sslkeystore.jks")
|
||||||
private val trustStorePath = directory.resolve("certificates").resolve("truststore.jks")
|
private val trustStorePath = directory.resolve("certificates").resolve("truststore.jks")
|
||||||
private val KEYSTORE_PASSWORD = "cordacadevpass" // TODO we need a proper way of managing keystores and passwords
|
private val KEYSTORE_PASSWORD = "cordacadevpass" // TODO we need a proper way of managing keystores and passwords
|
||||||
|
private val CIPHER_SUITES = listOf(
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256")
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(directory.fileSystem == FileSystems.getDefault()) { "Artemis only uses the default file system" }
|
require(directory.fileSystem == FileSystems.getDefault()) { "Artemis only uses the default file system" }
|
||||||
@ -321,9 +329,10 @@ class ArtemisMessagingService(val directory: Path,
|
|||||||
HOST_PROP_NAME to host,
|
HOST_PROP_NAME to host,
|
||||||
PORT_PROP_NAME to port.toInt(),
|
PORT_PROP_NAME to port.toInt(),
|
||||||
|
|
||||||
// Turn on AMQP support, which needs the protoclo jar on the classpath.
|
// Turn on AMQP support, which needs the protocol jar on the classpath.
|
||||||
// Unfortunately we cannot disable core protocol as artemis only uses AMQP for interop
|
// Unfortunately we cannot disable core protocol as artemis only uses AMQP for interop
|
||||||
// It does not use AMQP messages for its own
|
// It does not use AMQP messages for its own messages e.g. topology and heartbeats
|
||||||
|
// TODO further investigate how to ensure we use a well defined wire level protocol for Node to Node communications
|
||||||
PROTOCOLS_PROP_NAME to "CORE,AMQP",
|
PROTOCOLS_PROP_NAME to "CORE,AMQP",
|
||||||
|
|
||||||
// Enable TLS transport layer with client certs and restrict to at least SHA256 in handshake
|
// Enable TLS transport layer with client certs and restrict to at least SHA256 in handshake
|
||||||
@ -335,15 +344,15 @@ class ArtemisMessagingService(val directory: Path,
|
|||||||
TRUSTSTORE_PROVIDER_PROP_NAME to "JKS",
|
TRUSTSTORE_PROVIDER_PROP_NAME to "JKS",
|
||||||
TRUSTSTORE_PATH_PROP_NAME to trustStorePath,
|
TRUSTSTORE_PATH_PROP_NAME to trustStorePath,
|
||||||
TRUSTSTORE_PASSWORD_PROP_NAME to "trustpass",
|
TRUSTSTORE_PASSWORD_PROP_NAME to "trustpass",
|
||||||
ENABLED_CIPHER_SUITES_PROP_NAME to "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
|
ENABLED_CIPHER_SUITES_PROP_NAME to CIPHER_SUITES.joinToString(","),
|
||||||
ENABLED_PROTOCOLS_PROP_NAME to "TLSv1.2",
|
ENABLED_PROTOCOLS_PROP_NAME to "TLSv1.2",
|
||||||
NEED_CLIENT_AUTH_PROP_NAME to true
|
NEED_CLIENT_AUTH_PROP_NAME to true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strictly for dev only automatically construct a server certificate\private key signed from
|
* Strictly for dev only automatically construct a server certificate/private key signed from
|
||||||
* the CA certs in Node resources.
|
* the CA certs in Node resources. Then provision KeyStores into certificates folder under node path.
|
||||||
*/
|
*/
|
||||||
fun configureWithDevSSLCertificate() {
|
fun configureWithDevSSLCertificate() {
|
||||||
Files.createDirectories(directory.resolve("certificates"))
|
Files.createDirectories(directory.resolve("certificates"))
|
||||||
|
Loading…
Reference in New Issue
Block a user