mirror of
https://github.com/corda/corda.git
synced 2025-04-19 00:27:13 +00:00
ENT-2653: Add more options for providing distinct passwords for store and private keys. (#1580)
* ENT-2653: Add more options for providing distinct passwords for store and private keys. * ENT-2653: Documentation update.
This commit is contained in:
parent
58056d4ea9
commit
1d511269f6
@ -12,7 +12,7 @@ To run simply pass in the file or URL as the first parameter:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
> java -jar |jar_name| <file or URL>
|
||||
> java -jar |jar_name| <sub-command> <command line options>
|
||||
|
||||
..
|
||||
|
||||
@ -82,12 +82,13 @@ Command-line options
|
||||
ha-utilities generate-internal-ssl-keystores [-hvV] [--logging-level=<loggingLevel>] [-b=<baseDirectory>] [-c=<country>] [-l=<locality>] [-o=<organization>] [-p=<password>]
|
||||
|
||||
* ``-v``, ``--verbose``, ``--log-to-console``: If set, prints logging to the console as well as to a file.
|
||||
* ``--logging-level=<loggingLevel>``: Enable logging at this level and higher. Possible values:ERROR, WARN, INFO, DEBUG, TRACE. Default: INFO
|
||||
* ``-p``, ``--password=<password>``: Default password for all generated keystore and private keys. Default: changeit
|
||||
* ``--logging-level=<loggingLevel>``: Enable logging at this level and higher. Possible values: ERROR, WARN, INFO, DEBUG, TRACE. Default: INFO
|
||||
* ``-p``, ``--keyStorePassword=<keyStorePassword>``: Password for all generated keystores. Default: changeit
|
||||
* ``-e``, ``--entryPassword=<entryPassword>``: Password for all the keystores private keys. Default: changeit
|
||||
* ``-t``, ``--trustStorePassword=<trustStorePassword>``: Password for all the trust stores. Default: changeit
|
||||
* ``-o``, ``--organization=<organization>``: X500Name's organization attribute. Default: Corda
|
||||
* ``-l``, ``--locality=<locality>``: X500Name's locality attribute. Default: London
|
||||
* ``-c``, ``--country=<country>``: X500Name's country attribute. Default: GB
|
||||
* ``-b``, ``--base-directory=<baseDirectory>``: The node working directory where all the files are kept.
|
||||
* ``-h``, ``--help``: Show this help message and exit.
|
||||
* ``-V``, ``--version``: Print version information and exit.
|
||||
|
||||
* ``-V``, ``--version``: Print version information and exit.
|
@ -24,8 +24,12 @@ class InternalKeystoreGenerator : CliWrapperBase("generate-internal-ssl-keystore
|
||||
var baseDirectory: Path = Paths.get(".").toAbsolutePath().normalize()
|
||||
|
||||
// TODO: options to generate keys for different HA deployment mode?
|
||||
@Option(names = ["-p", "--password"], description = ["Default password for all generated keystore and private keys."], defaultValue = DEFAULT_PASSWORD)
|
||||
lateinit var password: String
|
||||
@Option(names = ["-p", "--keyStorePassword"], description = ["Password for all generated keystores."], defaultValue = DEFAULT_PASSWORD)
|
||||
lateinit var keyStorePassword: String
|
||||
@Option(names = ["-e", "--entryPassword"], description = ["Password for all the keystores private keys."], defaultValue = DEFAULT_PASSWORD)
|
||||
lateinit var entryPassword: String
|
||||
@Option(names = ["-t", "--trustStorePassword"], description = ["Password for all the trust stores."], defaultValue = DEFAULT_PASSWORD)
|
||||
lateinit var trustStorePassword: String
|
||||
@Option(names = ["-o", "--organization"], description = ["X500Name's organization attribute."], defaultValue = "Corda")
|
||||
lateinit var organization: String
|
||||
@Option(names = ["-u", "--organization-unit"], description = ["X500Name's organization unit attribute."], required = false)
|
||||
@ -38,42 +42,49 @@ class InternalKeystoreGenerator : CliWrapperBase("generate-internal-ssl-keystore
|
||||
override fun runProgram(): Int {
|
||||
// Create tunnel certs
|
||||
val tunnelCertDir = baseDirectory / "tunnel"
|
||||
val tunnelRoot = createRootKeystore("Internal Tunnel Root", tunnelCertDir / "tunnel-root.jks", tunnelCertDir / "tunnel-truststore.jks").getCertificateAndKeyPair(X509Utilities.CORDA_ROOT_CA, password)
|
||||
createTLSKeystore("float", tunnelRoot, tunnelCertDir / "float.jks")
|
||||
val tunnelRoot = createRootKeystore("Internal Tunnel Root", tunnelCertDir / "tunnel-root.jks", tunnelCertDir / "tunnel-truststore.jks",
|
||||
keyStorePassword, entryPassword, trustStorePassword).getCertificateAndKeyPair(X509Utilities.CORDA_ROOT_CA, entryPassword)
|
||||
createTLSKeystore("float", tunnelRoot, tunnelCertDir / "float.jks", keyStorePassword, entryPassword)
|
||||
createTLSKeystore("bridge", tunnelRoot, tunnelCertDir / "bridge.jks", keyStorePassword, entryPassword)
|
||||
|
||||
// Create artemis certs
|
||||
// NB: For Artemis store password must be the same as key password due to implementation restrictions.
|
||||
val artemisCertDir = baseDirectory / "artemis"
|
||||
val root = createRootKeystore("Internal Artemis Root", artemisCertDir / "artemis-root.jks", artemisCertDir / "artemis-truststore.jks").getCertificateAndKeyPair(X509Utilities.CORDA_ROOT_CA, password)
|
||||
createTLSKeystore("bridge", root, artemisCertDir / "bridge.jks")
|
||||
createTLSKeystore("artemis", root, artemisCertDir / "artemis.jks")
|
||||
createTLSKeystore("artemis-client", root, artemisCertDir / "artemis-client.jks")
|
||||
val root = createRootKeystore("Internal Artemis Root", artemisCertDir / "artemis-root.jks", artemisCertDir / "artemis-truststore.jks",
|
||||
keyStorePassword, keyStorePassword, trustStorePassword).getCertificateAndKeyPair(X509Utilities.CORDA_ROOT_CA, keyStorePassword)
|
||||
createTLSKeystore("bridge", root, artemisCertDir / "bridge.jks", keyStorePassword, keyStorePassword)
|
||||
createTLSKeystore("artemis", root, artemisCertDir / "artemis.jks", keyStorePassword, keyStorePassword)
|
||||
createTLSKeystore("artemis-client", root, artemisCertDir / "artemis-client.jks", keyStorePassword, keyStorePassword)
|
||||
|
||||
if (password == DEFAULT_PASSWORD) {
|
||||
println("Password is defaulted to $DEFAULT_PASSWORD, please change the keystores password using java keytool.")
|
||||
listOf(keyStorePassword to "keyStorePassword", entryPassword to "entryPassword", trustStorePassword to "trustStorePassword").forEach {
|
||||
if(it.first == DEFAULT_PASSWORD) {
|
||||
println("WARN: Password for '${it.second}' is defaulted to '$DEFAULT_PASSWORD'. Please consider changing the password using java keytool.")
|
||||
}
|
||||
}
|
||||
|
||||
return ExitCodes.SUCCESS
|
||||
}
|
||||
|
||||
private fun createRootKeystore(commonName: String, keystorePath: Path, trustStorePath: Path): X509KeyStore {
|
||||
private fun createRootKeystore(commonName: String, keystorePath: Path, trustStorePath: Path, storePassword: String, entryPassword: String, trustStorePassword: String): X509KeyStore {
|
||||
val key = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val rootCert = X509Utilities.createSelfSignedCACertificate(getX500Principal(commonName), key)
|
||||
val keystore = X509KeyStore.fromFile(keystorePath, password, createNew = true)
|
||||
val keystore = X509KeyStore.fromFile(keystorePath, storePassword, createNew = true)
|
||||
keystore.update {
|
||||
setPrivateKey(X509Utilities.CORDA_ROOT_CA, key.private, listOf(rootCert), password)
|
||||
setPrivateKey(X509Utilities.CORDA_ROOT_CA, key.private, listOf(rootCert), entryPassword)
|
||||
}
|
||||
println("$commonName keystore created in $keystorePath.")
|
||||
|
||||
X509KeyStore.fromFile(trustStorePath, password, createNew = true).setCertificate(X509Utilities.CORDA_ROOT_CA, rootCert)
|
||||
X509KeyStore.fromFile(trustStorePath, trustStorePassword, createNew = true).setCertificate(X509Utilities.CORDA_ROOT_CA, rootCert)
|
||||
println("$commonName truststore created in $trustStorePath.")
|
||||
|
||||
return keystore
|
||||
}
|
||||
|
||||
private fun createTLSKeystore(serviceName: String, root: CertificateAndKeyPair, keystorePath: Path) {
|
||||
private fun createTLSKeystore(serviceName: String, root: CertificateAndKeyPair, keystorePath: Path, storePassword: String, entryPassword: String) {
|
||||
val key = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val cert = X509Utilities.createCertificate(CertificateType.TLS, root.certificate, root.keyPair, getX500Principal(serviceName), key.public)
|
||||
X509KeyStore.fromFile(keystorePath, password, createNew = true).update {
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_TLS, key.private, listOf(cert, root.certificate), password)
|
||||
X509KeyStore.fromFile(keystorePath, storePassword, createNew = true).update {
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_TLS, key.private, listOf(cert, root.certificate), entryPassword)
|
||||
}
|
||||
println("Internal TLS keystore for '$serviceName' created in $keystorePath.")
|
||||
}
|
||||
|
@ -4,13 +4,16 @@ import net.corda.cliutils.CommonCliConstants.BASE_DIR
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.internal.exists
|
||||
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import org.assertj.core.api.Assertions
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_CLIENT_TLS
|
||||
import net.corda.nodeapi.internal.crypto.getCertificateAndKeyPair
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import picocli.CommandLine
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class InternalKeystoreGeneratorTest {
|
||||
@ -23,40 +26,52 @@ class InternalKeystoreGeneratorTest {
|
||||
@Test
|
||||
fun `generate keystores correctly`() {
|
||||
val workingDirectory = tempFolder.root.toPath()
|
||||
CommandLine.populateCommand(generator, BASE_DIR, workingDirectory.toString())
|
||||
Assertions.assertThat(generator.baseDirectory).isEqualTo(workingDirectory)
|
||||
val keyStorePassword = "keyStorePassword"
|
||||
val entryPassword = "entryPassword"
|
||||
val trustStorePassword = "trustStorePassword"
|
||||
CommandLine.populateCommand(generator,
|
||||
BASE_DIR, workingDirectory.toString(),
|
||||
"--keyStorePassword", keyStorePassword,
|
||||
"--entryPassword", entryPassword,
|
||||
"--trustStorePassword", trustStorePassword)
|
||||
assertEquals(workingDirectory, generator.baseDirectory)
|
||||
assertEquals(keyStorePassword, generator.keyStorePassword)
|
||||
assertEquals(entryPassword, generator.entryPassword)
|
||||
assertEquals(trustStorePassword, generator.trustStorePassword)
|
||||
generator.runProgram()
|
||||
|
||||
listOf("float.jks").map { workingDirectory / "tunnel" / it }.forEach {
|
||||
listOf("float.jks", "bridge.jks").map { workingDirectory / "tunnel" / it }.forEach {
|
||||
assertTrue(it.exists())
|
||||
assertTrue(X509KeyStore.fromFile(it, generator.password).contains(X509Utilities.CORDA_CLIENT_TLS))
|
||||
assertTrue(X509KeyStore.fromFile(it, generator.password).internal.isKeyEntry(X509Utilities.CORDA_CLIENT_TLS))
|
||||
assertTrue(X509KeyStore.fromFile(it, keyStorePassword).contains(CORDA_CLIENT_TLS))
|
||||
assertTrue(X509KeyStore.fromFile(it, keyStorePassword).internal.isKeyEntry(CORDA_CLIENT_TLS))
|
||||
assertNotNull(X509KeyStore.fromFile(it, keyStorePassword).internal.getCertificateAndKeyPair(CORDA_CLIENT_TLS, entryPassword))
|
||||
}
|
||||
|
||||
X509KeyStore.fromFile(workingDirectory / "tunnel" / "tunnel-root.jks", generator.password).update {
|
||||
assertTrue(contains(X509Utilities.CORDA_ROOT_CA))
|
||||
assertTrue(internal.isKeyEntry(X509Utilities.CORDA_ROOT_CA))
|
||||
X509KeyStore.fromFile(workingDirectory / "tunnel" / "tunnel-root.jks", keyStorePassword).update {
|
||||
assertTrue(contains(CORDA_ROOT_CA))
|
||||
assertTrue(internal.isKeyEntry(CORDA_ROOT_CA))
|
||||
assertNotNull(internal.getCertificateAndKeyPair(CORDA_ROOT_CA, entryPassword))
|
||||
}
|
||||
|
||||
X509KeyStore.fromFile(workingDirectory / "tunnel" / "tunnel-truststore.jks", generator.password).update {
|
||||
assertTrue(contains(X509Utilities.CORDA_ROOT_CA))
|
||||
assertFalse(internal.isKeyEntry(X509Utilities.CORDA_ROOT_CA))
|
||||
X509KeyStore.fromFile(workingDirectory / "tunnel" / "tunnel-truststore.jks", trustStorePassword).update {
|
||||
assertTrue(internal.isCertificateEntry(CORDA_ROOT_CA))
|
||||
assertFalse(internal.isKeyEntry(CORDA_ROOT_CA))
|
||||
}
|
||||
|
||||
listOf("bridge.jks", "artemis.jks", "artemis-client.jks").map { workingDirectory / "artemis" / it }.forEach {
|
||||
assertTrue(it.exists())
|
||||
assertTrue(X509KeyStore.fromFile(it, generator.password).contains(X509Utilities.CORDA_CLIENT_TLS))
|
||||
assertTrue(X509KeyStore.fromFile(it, generator.password).internal.isKeyEntry(X509Utilities.CORDA_CLIENT_TLS))
|
||||
assertTrue(X509KeyStore.fromFile(it, keyStorePassword).contains(CORDA_CLIENT_TLS))
|
||||
assertTrue(X509KeyStore.fromFile(it, keyStorePassword).internal.isKeyEntry(CORDA_CLIENT_TLS))
|
||||
}
|
||||
|
||||
X509KeyStore.fromFile(workingDirectory / "artemis" / "artemis-root.jks", generator.password).update {
|
||||
assertTrue(contains(X509Utilities.CORDA_ROOT_CA))
|
||||
assertTrue(internal.isKeyEntry(X509Utilities.CORDA_ROOT_CA))
|
||||
X509KeyStore.fromFile(workingDirectory / "artemis" / "artemis-root.jks", keyStorePassword).update {
|
||||
assertTrue(contains(CORDA_ROOT_CA))
|
||||
assertTrue(internal.isKeyEntry(CORDA_ROOT_CA))
|
||||
}
|
||||
|
||||
X509KeyStore.fromFile(workingDirectory / "artemis" / "artemis-truststore.jks", generator.password).update {
|
||||
assertTrue(contains(X509Utilities.CORDA_ROOT_CA))
|
||||
assertFalse(internal.isKeyEntry(X509Utilities.CORDA_ROOT_CA))
|
||||
X509KeyStore.fromFile(workingDirectory / "artemis" / "artemis-truststore.jks", trustStorePassword).update {
|
||||
assertTrue(contains(CORDA_ROOT_CA))
|
||||
assertFalse(internal.isKeyEntry(CORDA_ROOT_CA))
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user