From 2a0eefd3510945ed885bd1d609fd29bc49fbb930 Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Thu, 21 Dec 2017 13:54:10 +0000 Subject: [PATCH] Doorman generates trust store file, containing the root cert, instead of the .pem file (#241) --- network-management/{Readme.md => README.md} | 28 ++++++----- .../corda/networkmanage/common/utils/Utils.kt | 1 + .../doorman/DoormanParameters.kt | 2 - .../r3/corda/networkmanage/doorman/Main.kt | 48 +++++++++++-------- 4 files changed, 43 insertions(+), 36 deletions(-) rename network-management/{Readme.md => README.md} (84%) diff --git a/network-management/Readme.md b/network-management/README.md similarity index 84% rename from network-management/Readme.md rename to network-management/README.md index 8030d34427..fced2bb2cb 100644 --- a/network-management/Readme.md +++ b/network-management/README.md @@ -9,7 +9,7 @@ To build a fat jar containing all the doorman code you can simply invoke: The built file will appear in: ``` -network-management/capsule/build/libs/doorman-.jar +network-management/capsule/build/libs/doorman-.jar ``` ## HSM signing server To build a fat jar containing all the HSM signer code you can simply invoke: @@ -19,7 +19,7 @@ To build a fat jar containing all the HSM signer code you can simply invoke: The built file will appear in: ``` -network-management/capsule-hsm/build/libs/hsm-.jar +network-management/capsule-hsm/build/libs/hsm-.jar ``` The binaries can also be obtained from artifactory after deployment in TeamCity. @@ -28,12 +28,13 @@ To run the HSM signing server: ``` cd network-management -java -jar capsule-hsm/build/libs/hsm-3.0-NETWORKMAP-20171204.134345-6.jar --configFile hsm.conf +java -jar capsule-hsm/build/libs/hsm-.jar --configFile hsm.conf ``` For a list of options the HSM signing server takes, run with the `--help` option: - -java -jar capsule-hsm/build/libs/hsm-3.0-NETWORKMAP-20171204.134345-6.jar --help +``` +java -jar capsule-hsm/build/libs/hsm-3.0-.jar --help +``` #Configuring network management service ### Local signing @@ -143,8 +144,9 @@ networkMapConfig { java -jar doorman-.jar --mode CA_KEYGEN ``` - A root certificate `pem` file will also be created, this will be distributed to the client via a "out-of-band" process. - Note: We will be distributing a trust store instead of the pem file in future updates. + A trust store file containing the root trust certificate will be produced in the location `distribute-nodes / truststore.jks` + (relative to `rootStorePath`). `truststore.jks` must be copied to the `certificates` directory of each node before + they attempt to register. The trust store password is `trustpass`. ### 2. Start Doorman service for notary registration Start the network management server with the doorman service for initial bootstrapping. Network map service should be disabled at this point. @@ -154,11 +156,11 @@ networkMapConfig { ``` ### 3. Create notary node and register with the doorman - After the doorman service is started, copy the `rootcert.pem` file to the notaries' certificates folder and start the `initial-registration` process. + After the doorman service is started, start the notary node for the `initial-registration` process. -### 4. Add notary identities to the network parameter - The network parameter should contain the name and public key of the newly created notaries. - Example network parameter file: +### 4. Add notary identities to the network parameters + The network parameters should contain the name and public key of the newly created notaries. + Example network parameters file: notaries : [{ name: "O=Notary A, L=Port Louis, C=MU, OU=Org Unit, CN=Service Name" @@ -173,11 +175,11 @@ networkMapConfig { maxMessageSize = 100 maxTransactionSize = 100 - Save the parameters to `parameter.conf` + 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. We can now restart the network management server with both doorman and network map service. ``` -java -jar doorman-.jar --update-network-parameter parameter.conf +java -jar doorman-.jar --update-network-parameter network-parameters.conf ``` diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/Utils.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/Utils.kt index e95b3da1b4..f1647de6bd 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/Utils.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/Utils.kt @@ -39,6 +39,7 @@ fun Array.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()) diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/DoormanParameters.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/DoormanParameters.kt index ca22c89a78..9f786756ee 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/DoormanParameters.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/DoormanParameters.kt @@ -34,7 +34,6 @@ data class NetworkManagementServerParameters(// TODO: Move local signing to sign val rootKeystorePassword: String?, // TODO Should be part of a localSigning sub-config val rootPrivateKeyPassword: String? - ) { companion object { // TODO: Do we really need these defaults? @@ -79,7 +78,6 @@ fun parseParameters(vararg args: String): NetworkManagementServerParameters { .describedAs("filepath") accepts("update-network-parameters", "Update network parameters filepath. Currently only network parameters initialisation is supported.") .withRequiredArg() - .describedAs("The new network map") .describedAs("filepath") accepts("mode", "Set the mode of this application") .withRequiredArg() diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt index 1779dfcbab..13f5bac03b 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt @@ -5,7 +5,6 @@ import com.r3.corda.networkmanage.common.persistence.* import com.r3.corda.networkmanage.common.persistence.CertificationRequestStorage.Companion.DOORMAN_SIGNATURE import com.r3.corda.networkmanage.common.signer.NetworkMapSigner import com.r3.corda.networkmanage.common.utils.ShowHelpException -import com.r3.corda.networkmanage.common.utils.toX509Certificate import com.r3.corda.networkmanage.doorman.signer.DefaultCsrHandler import com.r3.corda.networkmanage.doorman.signer.JiraCsrHandler import com.r3.corda.networkmanage.doorman.signer.LocalSigner @@ -14,6 +13,7 @@ import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService import com.r3.corda.networkmanage.doorman.webservice.RegistrationWebService import net.corda.core.crypto.Crypto import net.corda.core.identity.CordaX500Name +import net.corda.core.internal.cert import net.corda.core.internal.createDirectories import net.corda.core.internal.div import net.corda.core.serialization.internal.SerializationEnvironmentImpl @@ -169,52 +169,58 @@ internal fun readPassword(fmt: String): String { } // Keygen utilities. -// TODO: Move keygen methods to Utilities.kt -fun generateRootKeyPair(rootStorePath: Path, rootKeystorePass: String?, rootPrivateKeyPass: String?) { +fun generateRootKeyPair(rootStoreFile: Path, rootKeystorePass: String?, rootPrivateKeyPass: String?) { println("Generating Root CA keypair and certificate.") // Get password from console if not in config. val rootKeystorePassword = rootKeystorePass ?: readPassword("Root Keystore Password: ") // Ensure folder exists. - rootStorePath.parent.createDirectories() - val rootStore = loadOrCreateKeyStore(rootStorePath, rootKeystorePassword) + rootStoreFile.parent.createDirectories() + val rootStore = loadOrCreateKeyStore(rootStoreFile, rootKeystorePassword) val rootPrivateKeyPassword = rootPrivateKeyPass ?: readPassword("Root Private Key Password: ") if (rootStore.containsAlias(X509Utilities.CORDA_ROOT_CA)) { - val oldKey = loadOrCreateKeyStore(rootStorePath, rootKeystorePassword).getCertificate(X509Utilities.CORDA_ROOT_CA).publicKey + val oldKey = loadOrCreateKeyStore(rootStoreFile, rootKeystorePassword).getCertificate(X509Utilities.CORDA_ROOT_CA).publicKey println("Key ${X509Utilities.CORDA_ROOT_CA} already exists in keystore, process will now terminate.") println(oldKey) exitProcess(1) } val selfSignKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) - val selfSignCert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Root CA", organisation = "R3 Ltd", locality = "London", country = "GB", organisationUnit = "Corda", state = null), selfSignKey) + // TODO Make the cert subject configurable + val selfSignCert = X509Utilities.createSelfSignedCACertificate( + CordaX500Name(commonName = "Corda Root CA", organisation = "R3 Ltd", locality = "London", country = "GB", organisationUnit = "Corda", state = null), + selfSignKey).cert rootStore.addOrReplaceKey(X509Utilities.CORDA_ROOT_CA, selfSignKey.private, rootPrivateKeyPassword.toCharArray(), arrayOf(selfSignCert)) - rootStore.save(rootStorePath, rootKeystorePassword) + rootStore.save(rootStoreFile, rootKeystorePassword) - // TODO: remove this once we create truststore for nodes. - X509Utilities.saveCertificateAsPEMFile(selfSignCert.toX509Certificate(), rootStorePath.parent / "rootcert.pem") + val nodeTrustStoreFile = (rootStoreFile.parent / "distribute-nodes").createDirectories() / "truststore.jks" + // TODO The password for trust store must be a config option + val nodeTrustStore = loadOrCreateKeyStore(nodeTrustStoreFile, "trustpass") + nodeTrustStore.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, selfSignCert) + nodeTrustStore.save(nodeTrustStoreFile, "trustpass") + println("Trust store for distribution to nodes created in $nodeTrustStore") - println("Root CA keypair and certificate stored in ${rootStorePath.toAbsolutePath()}.") - println(loadKeyStore(rootStorePath, rootKeystorePassword).getCertificate(X509Utilities.CORDA_ROOT_CA).publicKey) + println("Root CA keypair and certificate stored in ${rootStoreFile.toAbsolutePath()}.") + println(loadKeyStore(rootStoreFile, rootKeystorePassword).getCertificate(X509Utilities.CORDA_ROOT_CA).publicKey) } -fun generateCAKeyPair(keystorePath: Path, rootStorePath: Path, rootKeystorePass: String?, rootPrivateKeyPass: String?, keystorePass: String?, caPrivateKeyPass: String?) { - println("Generating Intermediate CA keypair and certificate using root keystore $rootStorePath.") +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.") // Get password from console if not in config. val rootKeystorePassword = rootKeystorePass ?: readPassword("Root Keystore Password: ") val rootPrivateKeyPassword = rootPrivateKeyPass ?: readPassword("Root Private Key Password: ") - val rootKeyStore = loadKeyStore(rootStorePath, rootKeystorePassword) + val rootKeyStore = loadKeyStore(rootStoreFile, rootKeystorePassword) val rootKeyAndCert = rootKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_ROOT_CA, rootPrivateKeyPassword) val keystorePassword = keystorePass ?: readPassword("Keystore Password: ") val caPrivateKeyPassword = caPrivateKeyPass ?: readPassword("CA Private Key Password: ") // Ensure folder exists. - keystorePath.parent.createDirectories() - val keyStore = loadOrCreateKeyStore(keystorePath, keystorePassword) + keystoreFile.parent.createDirectories() + val keyStore = loadOrCreateKeyStore(keystoreFile, keystorePassword) if (keyStore.containsAlias(X509Utilities.CORDA_INTERMEDIATE_CA)) { - val oldKey = loadOrCreateKeyStore(keystorePath, rootKeystorePassword).getCertificate(X509Utilities.CORDA_INTERMEDIATE_CA).publicKey + 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) @@ -225,9 +231,9 @@ fun generateCAKeyPair(keystorePath: Path, rootStorePath: Path, rootKeystorePass: CordaX500Name(commonName = "Corda Intermediate CA", organisation = "R3 Ltd", organisationUnit = "Corda", locality = "London", country = "GB", state = null), intermediateKey.public) keyStore.addOrReplaceKey(X509Utilities.CORDA_INTERMEDIATE_CA, intermediateKey.private, caPrivateKeyPassword.toCharArray(), arrayOf(intermediateCert, rootKeyAndCert.certificate)) - keyStore.save(keystorePath, keystorePassword) - println("Intermediate CA keypair and certificate stored in $keystorePath.") - println(loadKeyStore(keystorePath, keystorePassword).getCertificate(X509Utilities.CORDA_INTERMEDIATE_CA).publicKey) + keyStore.save(keystoreFile, keystorePassword) + println("Intermediate CA keypair and certificate stored in $keystoreFile.") + println(loadKeyStore(keystoreFile, keystorePassword).getCertificate(X509Utilities.CORDA_INTERMEDIATE_CA).publicKey) }