mirror of
https://github.com/corda/corda.git
synced 2024-12-27 08:22:35 +00:00
Adding HSM signing service docs (#122)
* Adding HSM signing service docs * Addressing review comments * Addressing review comments - round 2 * Addressing review comments - round 3 * Fixing method comment
This commit is contained in:
parent
c516a4b028
commit
c5e17d90f2
BIN
docs/source/resources/hsm_csr_signing_flow.pdf
Normal file
BIN
docs/source/resources/hsm_csr_signing_flow.pdf
Normal file
Binary file not shown.
@ -7,12 +7,12 @@ See the Readme in under ``network-management`` for detailed building instruction
|
||||
|
||||
Configuration file
|
||||
------------------
|
||||
At startup Doorman reads a configuration file, passed with ``--configFile`` on the command line.
|
||||
At startup doorman reads a configuration file, passed with ``--configFile`` on the command line.
|
||||
|
||||
This is an example of what a Doorman configuration file might look like:
|
||||
This is an example of what a doorman configuration file might look like:
|
||||
.. literalinclude:: ../../network-management/doorman.conf
|
||||
|
||||
Invoke Doorman with ``-?`` for a full list of supported command-line arguments.
|
||||
Invoke doorman with ``-?`` for a full list of supported command-line arguments.
|
||||
|
||||
|
||||
Configuration parameters
|
||||
@ -51,7 +51,9 @@ Allowed parameters are:
|
||||
|
||||
:doneTransitionCode: Jira status to put approved tickets in
|
||||
|
||||
:keystorePath: Path for the keystore
|
||||
:keystorePath: Path for the keystore. If not set (or null is passed) doorman will NOT perform any signing.
|
||||
This is required in case of the HSM integration where signing process is offloaded (from doorman) to an external service
|
||||
that binds with an HSM.
|
||||
|
||||
:rootStorePath: Path for the root keystore
|
||||
|
||||
@ -61,7 +63,7 @@ Allowed parameters are:
|
||||
|
||||
Bootstrapping the network parameters
|
||||
------------------------------------
|
||||
When Doorman is running it will serve the current network parameters. The first time Doorman is
|
||||
When doorman is running it will serve the current network parameters. The first time doorman is
|
||||
started it will need to know the initial value for the network parameters.
|
||||
|
||||
The initial values for the network parameters can be specified with a file, like this:
|
||||
@ -71,6 +73,21 @@ And the location of that file can be specified with: ``--initialNetworkParameter
|
||||
Note that when reading from file:
|
||||
|
||||
1. ``epoch`` will always be set to 1,
|
||||
2. ``modifiedTime`` will be the Doorman startup time
|
||||
2. ``modifiedTime`` will be the doorman startup time
|
||||
|
||||
``epoch`` will increase by one every time the network parameters are updated.
|
||||
|
||||
Bootstrapping the network map
|
||||
-----------------------------
|
||||
|
||||
The network map is periodically refreshed, with frequency driven by the 'signInterval' parameter when local signing is in use.
|
||||
In case of an external signing service it depends on that service configuration. Due to the design decisions dictated by the security concerns
|
||||
around the external signing service, doorman is not allowed to connect directly with the signing sevice. Instead, the external service is
|
||||
expected to access the doorman database in order to obtain signature requiring data.
|
||||
Therefore, doorman takes a passive role considering all signing process related aspects.
|
||||
Network map refresh happens only if there is a change to the current one (i.e. most recently created version of the network map).
|
||||
See the :doc:`signing-service` for a more detailed description of the service.
|
||||
|
||||
When dealing with a fresh deployment (i.e. no previous data is present in the doorman database),
|
||||
it may take some time until the network map is available. This is caused by the aforementioned decoupling of the signing
|
||||
process from doorman itself.
|
76
docs/source/running-signing-service.rst
Normal file
76
docs/source/running-signing-service.rst
Normal file
@ -0,0 +1,76 @@
|
||||
Running the signing service
|
||||
===========================
|
||||
|
||||
The signing service is a bridge between the networking service and the HSM infrastructure. It is responsible for retrieving
|
||||
pending requests for signatures and managing the process of securing these signatures from an HSM infrastructure.
|
||||
|
||||
The signing service has a console-based user interface (designed for the manual signing process of the certificate signing requests),
|
||||
which upon successful startup should display different options to the user.
|
||||
At the same time, it connects to the database (which is expected to be shared with Doorman)
|
||||
and periodically polls it and if needed automatically signs the following: network map and certificate revocation list.
|
||||
|
||||
See the :doc:`signing-service` for a more detailed description of the service.
|
||||
|
||||
Configuration file
|
||||
------------------
|
||||
At startup the signing service reads a configuration file, passed with ``--configFile`` on the command line.
|
||||
|
||||
This is an example of what a signing service configuration file might look like:
|
||||
.. literalinclude:: ../../network-management/hsm.conf
|
||||
|
||||
Invoke the signing service with ``-?`` for a full list of supported command-line arguments.
|
||||
|
||||
|
||||
Configuration parameters
|
||||
------------------------
|
||||
Allowed parameters are:
|
||||
|
||||
:device: HSM connection string. It is of the following format 3001@127.0.0.1, where 3001 is the port number.
|
||||
Default value: "3001@127.0.0.1"
|
||||
|
||||
:keyGroup: HSM key group. This parameter is vendor specific (see Utimaco docs).
|
||||
|
||||
:keySpecifier: HSM key specifier. This parameter is vendor specific (see Utimaco docs). Default value: 1
|
||||
|
||||
:rootPrivateKeyPassword: Private key password for the root certificate.
|
||||
|
||||
:rootCertificateName: Root certificate name. Default value: "cordarootca"
|
||||
|
||||
:csrPrivateKeyPassword: Private key password for the intermediate certificate used to sign certficate signing requests.
|
||||
|
||||
:csrCertificateName: Certificate signing requests intermediate certificate name. Default value: "cordaintermediateca"
|
||||
|
||||
:databaseProperties: Database properties.
|
||||
|
||||
:dataSourceProperties: Data source properties. It should describe (or point to) the Doorman database.
|
||||
|
||||
:networkMapCertificateName: Network map intermediate certificate name. Default value: "cordaintermediateca_nm"
|
||||
|
||||
:networkMapPrivateKeyPassword: Private key password for the intermediate certificate used to sign the network map.
|
||||
|
||||
:validDays: Number of days issued signatures are valid for.
|
||||
|
||||
:signAuthThreshold: Minimum authentication strength threshold required for certificate signing requests.
|
||||
Default value: 2
|
||||
|
||||
:keyGenAuthThreshold: Minimum authentication strength threshold required for key generation.
|
||||
Default value: 2
|
||||
|
||||
:authMode: Authentication mode, used when validating a user for certificate signing request signature.
|
||||
Allowed values are:
|
||||
"PASSWORD" (default) - type-in password authentication
|
||||
CARD_READER - smart card reader authentication
|
||||
KEY_FILE - key file authentication
|
||||
|
||||
:authKeyFilePath: Authentication key file. It is used when the 'authMode' is set to "KEY_FILE"
|
||||
or for the automated signing process - e.g. network map, certificate revocation list. Default value: null
|
||||
|
||||
:authKeyFilePassword: Authentication key file password. It is used when the 'authMode' is set to "KEY_FILE"
|
||||
or for the automated signing process - e.g. network map, certificate revocation list. Default value: null
|
||||
|
||||
:signInterval: Interval (in seconds) in which all automated signing happens. Default value: 600 seconds
|
||||
|
||||
Expected behaviour and output upon the service start-up
|
||||
-------------------------------------------------------
|
||||
|
||||
A commandline-based interface (with different menu options) is presented to a user.
|
77
docs/source/signing-service.rst
Normal file
77
docs/source/signing-service.rst
Normal file
@ -0,0 +1,77 @@
|
||||
HSM Signing Service
|
||||
===================
|
||||
|
||||
The HSM Signing Service is designed to act as a bridge between the networking service and the HSM infrastructure.
|
||||
Due to possible security concerns, the signing service is meant to be hosted on private premises and not in a cloud environment.
|
||||
That does not apply to the networking service, which may be hosted by a cloud provider. Such a design allows for, and in fact
|
||||
was driven by the requirement of, permitting only outgoing connections between the two deployments (i.e. private and cloud).
|
||||
|
||||
Having this deployment design in mind, the signing service initiates connection to the networking service database and
|
||||
retrieves all the data that has to be signed.
|
||||
This retrieval happens automatically (based on the pre-configured time interval) in case of Network Map and Certificate Revocation List signing.
|
||||
The on-demand approach applies only in case of Certificate Signing Requests signatures as they involve human interaction (for authentication credentials input).
|
||||
For that purpose, the service provides a commandline-based interface and guides the user throughout the signing process.
|
||||
|
||||
The signing service assumes an HSM configuration in place - i.e. all users and certificates should be set-up on the HSM box,
|
||||
prior to the signing service deployment and usage. Nevertheless, currently, the signing service comes with a simple utility
|
||||
that allows an authenticated HSM user to generate the root and intermediate certificates. The utility is only a temporary
|
||||
solution and should NOT be used in case of production deployment. This convenience feature will be removed in a future release.
|
||||
|
||||
Following, are the steps for the signing service operation with respect to every kind of object it signs:
|
||||
|
||||
Certificate Signing Request Steps
|
||||
---------------------------------
|
||||
|
||||
* The networking service receives a certificate signing request and approves it (more specifically the certificate signing request is approved using an external ticket tracking tool - e.g. Jira).
|
||||
It is ready to be signed.
|
||||
|
||||
* A privileged user chooses (using the commandline interface) that she wants to sign the approved requests.
|
||||
|
||||
* A connection to the networking service database is established and all approved requests are fetched and listed to the user.
|
||||
|
||||
* After selecting an appropriate option (either signing all approved requests or just some of them) user is prompted for her username (in terms of the HSM setup).
|
||||
|
||||
* Next step is to confirm user's identity against the HSM. In this case, the signing service supports two authentication methods: Password or Card Reader.
|
||||
|
||||
* If the user's identity is confirmed (using one of the above methods) and her privileges are strong enough, then the signing process commences using the configured intermediate certificate.
|
||||
|
||||
* After that, the networking service database is updated with the signed certificates.
|
||||
|
||||
* In case of insufficient user privileges, the service will prompt for another user to be authenticated.
|
||||
|
||||
Visualised steps available as :download:`pdf <resources/hsm_csr_signing_flow.pdf>`
|
||||
|
||||
|
||||
Certificate Revocation List Steps
|
||||
---------------------------------
|
||||
|
||||
* The networking service receives a certificate revocation request and approves it (more specifically the certificate signing request is approved using an external ticket tracking tool - e.g. Jira).
|
||||
It is ready to be included into the certificate revocation list.
|
||||
|
||||
* Periodically (the time interval is pre-configured at the deployment time), the signing service fetches all approved certificate revocation requests. If the list is empty, then nothing happens and means that the current Certificate Revocation List remains unchanged.
|
||||
|
||||
* If there is at least one approved certificate revocation request, it means that a new certificate revocation list needs to be created and signed.
|
||||
|
||||
* In such a case, the service fetches all (already) revoked certificate revocation requests
|
||||
|
||||
* It builds a new certificate revocation list that combines already revoked requests and approved ones.
|
||||
|
||||
* The list is signed on HSM with an intermediate certificate whose name (together with the auto-user credentials) was pre-configured at the signing service deployment time
|
||||
|
||||
* The signed list is serialised and stored in the networking service database ready to be served. Also, all approved requests become revoked now.
|
||||
|
||||
|
||||
Signing Network Map
|
||||
-------------------
|
||||
|
||||
* The networking service receives a new (or updated) node info.
|
||||
|
||||
* Periodically (the time interval is pre-configured at the deployment time), the signing service fetches from the database current network map, all node info objects with valid certificates and current network parameters.
|
||||
|
||||
* A new network map object is created out of the fetched data.
|
||||
|
||||
* If the new network map hash does not differ from the current network map hash, then nothing happens and current network map remains unchanged.
|
||||
|
||||
* If they are different, then the newly created network map object is serialized using the Corda AMQP serialisation format and signed by the dedicated intermediate certificate stored in HSM.
|
||||
|
||||
* Once signed, the new network map data is stored in the networking service database and available for nodes to retrieve when they next poll for the network map.
|
25
network-management/hsm.conf
Normal file
25
network-management/hsm.conf
Normal file
@ -0,0 +1,25 @@
|
||||
device = "3001@127.0.0.1"
|
||||
keyGroup = "DEV.DOORMAN"
|
||||
keySpecifier = -1
|
||||
authMode = PASSWORD
|
||||
rootCertificateName = "corda_root_ca"
|
||||
rootPrivateKeyPassword = "Password"
|
||||
csrPrivateKeyPassword = "Password"
|
||||
csrCertificateName = "intermediate_ca"
|
||||
networkMapCertificateName = "intermediate_ca"
|
||||
networkMapPrivateKeyPassword = "Password"
|
||||
validDays = 3650
|
||||
signAuthThreshold = 2
|
||||
keyGenAuthThreshold = 2
|
||||
authKeyFilePath = "./Administrator.key"
|
||||
authKeyFilePassword = "Password"
|
||||
autoUsername = "AUTO_USER"
|
||||
signInterval = 600
|
||||
|
||||
h2port = 0
|
||||
dataSourceProperties {
|
||||
"dataSourceClassName" = org.h2.jdbcx.JdbcDataSource
|
||||
"dataSource.url" = "jdbc:h2:file:"${basedir}"/persistence;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;WRITE_DELAY=0;AUTO_SERVER_PORT="${h2port}
|
||||
"dataSource.user" = sa
|
||||
"dataSource.password" = ""
|
||||
}
|
@ -24,7 +24,12 @@ import java.util.*
|
||||
fun main(args: Array<String>) {
|
||||
run(Parameters(
|
||||
dataSourceProperties = makeTestDataSourceProperties(),
|
||||
databaseProperties = makeNotInitialisingTestDatabaseProperties()
|
||||
databaseProperties = makeNotInitialisingTestDatabaseProperties(),
|
||||
csrPrivateKeyPassword = "",
|
||||
networkMapPrivateKeyPassword = "",
|
||||
rootPrivateKeyPassword = "",
|
||||
keyGroup = "DEV.DOORMAN",
|
||||
validDays = 3650
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,11 @@ class HsmTest {
|
||||
dataSourceProperties = mock(),
|
||||
device = "${hsmSimulator.port}@${hsmSimulator.host}",
|
||||
keySpecifier = 1,
|
||||
keyGroup = "*"
|
||||
csrPrivateKeyPassword = "",
|
||||
networkMapPrivateKeyPassword = "",
|
||||
rootPrivateKeyPassword = "",
|
||||
keyGroup = "DEV.DOORMAN",
|
||||
validDays = 3650
|
||||
)
|
||||
|
||||
@Rule
|
||||
|
@ -21,7 +21,7 @@ fun PublicKey.hashString() = encoded.sha256().toString()
|
||||
|
||||
fun Array<out String>.toConfigWithOptions(registerOptions: OptionParser.() -> Unit): Config {
|
||||
val parser = OptionParser()
|
||||
val helpOption = parser.acceptsAll(listOf("h", "?", "help"), "show help").forHelp();
|
||||
val helpOption = parser.acceptsAll(listOf("h", "?", "help"), "show help").forHelp()
|
||||
registerOptions(parser)
|
||||
val optionSet = parser.parse(*this)
|
||||
// Print help and exit on help option.
|
||||
|
@ -17,9 +17,13 @@ import java.nio.file.Paths
|
||||
import java.time.Duration
|
||||
import java.util.*
|
||||
|
||||
data class DoormanParameters(val keystorePassword: String?,
|
||||
data class DoormanParameters(// TODO Create a localSigning sub-config and put that there
|
||||
val keystorePassword: String?,
|
||||
// TODO Should be part of a localSigning sub-config
|
||||
val caPrivateKeyPassword: String?,
|
||||
// TODO Should be part of a localSigning sub-config
|
||||
val rootKeystorePassword: String?,
|
||||
// TODO Should be part of a localSigning sub-config
|
||||
val rootPrivateKeyPassword: String?,
|
||||
val host: String,
|
||||
val port: Int,
|
||||
@ -28,10 +32,13 @@ data class DoormanParameters(val keystorePassword: String?,
|
||||
val approveAll: Boolean = false,
|
||||
val databaseProperties: Properties? = null,
|
||||
val jiraConfig: JiraConfig? = null,
|
||||
// TODO Should be part of a localSigning sub-config
|
||||
val keystorePath: Path? = null,
|
||||
// TODO Should be part of a localSigning sub-config
|
||||
val rootStorePath: Path? = null,
|
||||
// TODO Change these to Duration in the future
|
||||
val approveInterval: Long = DEFAULT_APPROVE_INTERVAL,
|
||||
// TODO Should be part of a localSigning sub-config
|
||||
val signInterval: Long = DEFAULT_SIGN_INTERVAL
|
||||
) {
|
||||
enum class Mode {
|
||||
|
@ -34,31 +34,28 @@ fun run(parameters: Parameters) {
|
||||
val hsmNetworkMapSigningThread = HsmNetworkMapSigner(
|
||||
networkMapStorage,
|
||||
networkMapCertificateName,
|
||||
networkMapPrivateKeyPass,
|
||||
keyStorePass,
|
||||
Authenticator(createProvider(), AuthMode.KEY_FILE, autoUsername, authKeyFilePath, authKeyFilePass, signAuthThreshold)).start()
|
||||
networkMapPrivateKeyPassword,
|
||||
Authenticator(createProvider(), AuthMode.KEY_FILE, autoUsername, authKeyFilePath, authKeyFilePassword, signAuthThreshold)).start()
|
||||
val sign: (List<ApprovedCertificateRequestData>) -> Unit = {
|
||||
val signer = HsmCsrSigner(
|
||||
csrStorage,
|
||||
csrCertificateName,
|
||||
csrPrivateKeyPass,
|
||||
csrPrivateKeyPassword,
|
||||
rootCertificateName,
|
||||
validDays,
|
||||
keyStorePass,
|
||||
Authenticator(createProvider(), authMode, autoUsername, authKeyFilePath, authKeyFilePass, signAuthThreshold))
|
||||
Authenticator(createProvider(), authMode, autoUsername, authKeyFilePath, authKeyFilePassword, signAuthThreshold))
|
||||
signer.sign(it)
|
||||
}
|
||||
Menu().withExceptionHandler(::processError).addItem("1", "Generate root and intermediate certificates", {
|
||||
if (confirmedKeyGen()) {
|
||||
val generator = KeyCertificateGenerator(
|
||||
Authenticator(createProvider(), authMode, autoUsername, authKeyFilePath, authKeyFilePass, keyGenAuthThreshold),
|
||||
Authenticator(createProvider(), authMode, autoUsername, authKeyFilePath, authKeyFilePassword, keyGenAuthThreshold),
|
||||
keySpecifier,
|
||||
keyGroup)
|
||||
generator.generateAllCertificates(
|
||||
keyStorePass,
|
||||
listOf(CertificateNameAndPass(csrCertificateName, csrPrivateKeyPass), CertificateNameAndPass(networkMapCertificateName, networkMapPrivateKeyPass)),
|
||||
listOf(CertificateNameAndPass(csrCertificateName, csrPrivateKeyPassword), CertificateNameAndPass(networkMapCertificateName, networkMapPrivateKeyPassword)),
|
||||
rootCertificateName,
|
||||
rootPrivateKeyPass,
|
||||
rootPrivateKeyPassword,
|
||||
validDays)
|
||||
}
|
||||
}).addItem("2", "Sign all approved and unsigned CSRs", {
|
||||
|
@ -6,12 +6,10 @@ import com.r3.corda.networkmanage.hsm.configuration.Parameters.Companion.DEFAULT
|
||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters.Companion.DEFAULT_CSR_CERTIFICATE_NAME
|
||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters.Companion.DEFAULT_DEVICE
|
||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters.Companion.DEFAULT_KEY_GEN_AUTH_THRESHOLD
|
||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters.Companion.DEFAULT_KEY_GROUP
|
||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters.Companion.DEFAULT_KEY_SPECIFIER
|
||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters.Companion.DEFAULT_ROOT_CERTIFICATE_NAME
|
||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters.Companion.DEFAULT_SIGN_AUTH_THRESHOLD
|
||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters.Companion.DEFAULT_SIGN_INTERVAL
|
||||
import com.r3.corda.networkmanage.hsm.configuration.Parameters.Companion.DEFAULT_VALID_DAYS
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import com.typesafe.config.ConfigParseOptions
|
||||
import net.corda.core.internal.div
|
||||
@ -28,24 +26,23 @@ data class Parameters(val basedir: Path = Paths.get("."),
|
||||
val dataSourceProperties: Properties,
|
||||
val databaseProperties: Properties? = null,
|
||||
val device: String = DEFAULT_DEVICE,
|
||||
val keyStorePass: String? = null,
|
||||
// TODO this needs cleaning up after the config-file-only support is implemented
|
||||
val keyGroup: String = DEFAULT_KEY_GROUP,
|
||||
val keyGroup: String,
|
||||
val keySpecifier: Int = DEFAULT_KEY_SPECIFIER,
|
||||
val rootPrivateKeyPass: String = DEFAULT_ROOT_PRIVATE_KEY,
|
||||
val csrPrivateKeyPass: String = DEFAULT_CSR_PRIVATE_KEY,
|
||||
val rootPrivateKeyPassword: String,
|
||||
val csrPrivateKeyPassword: String,
|
||||
val csrCertificateName: String = DEFAULT_CSR_CERTIFICATE_NAME,
|
||||
val networkMapCertificateName: String = DEFAULT_NETWORK_MAP_CERTIFICATE_NAME,
|
||||
val networkMapPrivateKeyPass: String = DEFAULT_NETWORK_MAP_PRIVATE_KEY_PASS,
|
||||
val networkMapPrivateKeyPassword: String,
|
||||
val rootCertificateName: String = DEFAULT_ROOT_CERTIFICATE_NAME,
|
||||
val validDays: Int = DEFAULT_VALID_DAYS,
|
||||
val validDays: Int,
|
||||
val signAuthThreshold: Int = DEFAULT_SIGN_AUTH_THRESHOLD,
|
||||
val keyGenAuthThreshold: Int = DEFAULT_KEY_GEN_AUTH_THRESHOLD,
|
||||
val authMode: AuthMode = DEFAULT_AUTH_MODE,
|
||||
val authKeyFilePath: Path? = DEFAULT_KEY_FILE_PATH,
|
||||
val authKeyFilePass: String? = DEFAULT_KEY_FILE_PASS,
|
||||
val authKeyFilePassword: String? = DEFAULT_KEY_FILE_PASSWORD,
|
||||
val autoUsername: String? = DEFAULT_AUTO_USERNAME,
|
||||
// TODO Change this to Duration in the future
|
||||
// TODO Change this to Duration in the future.
|
||||
val signInterval: Long = DEFAULT_SIGN_INTERVAL) {
|
||||
companion object {
|
||||
val DEFAULT_DEVICE = "3001@127.0.0.1"
|
||||
@ -54,16 +51,11 @@ data class Parameters(val basedir: Path = Paths.get("."),
|
||||
val DEFAULT_KEY_GEN_AUTH_THRESHOLD = 2
|
||||
val DEFAULT_CSR_CERTIFICATE_NAME = X509Utilities.CORDA_INTERMEDIATE_CA
|
||||
val DEFAULT_ROOT_CERTIFICATE_NAME = X509Utilities.CORDA_ROOT_CA
|
||||
val DEFAULT_VALID_DAYS = 3650
|
||||
val DEFAULT_KEY_GROUP = "DEV.DOORMAN"
|
||||
val DEFAULT_KEY_SPECIFIER = 1
|
||||
val DEFAULT_KEY_FILE_PATH: Path? = null //Paths.get("/Users/michalkit/WinDev1706Eval/Shared/TEST4.key")
|
||||
val DEFAULT_KEY_FILE_PASS: String? = null
|
||||
val DEFAULT_KEY_FILE_PASSWORD: String? = null
|
||||
val DEFAULT_AUTO_USERNAME: String? = null
|
||||
val DEFAULT_CSR_PRIVATE_KEY = ""
|
||||
val DEFAULT_ROOT_PRIVATE_KEY = ""
|
||||
val DEFAULT_NETWORK_MAP_CERTIFICATE_NAME = "cordaintermediateca_nm"
|
||||
val DEFAULT_NETWORK_MAP_PRIVATE_KEY_PASS = ""
|
||||
val DEFAULT_SIGN_INTERVAL = 600L // in seconds (10 minutes)
|
||||
}
|
||||
}
|
||||
@ -78,20 +70,19 @@ fun parseParameters(vararg args: String): Parameters {
|
||||
accepts("basedir", "Overriding configuration filepath, default to current directory.").withRequiredArg().defaultsTo(".").describedAs("filepath")
|
||||
accepts("configFile", "Overriding configuration file. (default: <<current directory>>/node.conf)").withRequiredArg().describedAs("filepath")
|
||||
accepts("device", "CryptoServer device address (default: $DEFAULT_DEVICE)").withRequiredArg()
|
||||
accepts("keyStorePass", "Password for the key store").withRequiredArg().describedAs("password")
|
||||
accepts("keyGroup", "CryptoServer key group (default: $DEFAULT_KEY_GROUP)").withRequiredArg().defaultsTo(DEFAULT_KEY_GROUP)
|
||||
accepts("keyGroup", "CryptoServer key group").withRequiredArg()
|
||||
accepts("keySpecifier", "CryptoServer key specifier (default: $DEFAULT_KEY_SPECIFIER)").withRequiredArg().ofType(Int::class.java).defaultsTo(DEFAULT_KEY_SPECIFIER)
|
||||
accepts("rootPrivateKeyPass", "Password for the root certificate private key").withRequiredArg().describedAs("password")
|
||||
accepts("csrPrivateKeyPass", "Password for the CSR signing certificate private key").withRequiredArg().describedAs("password")
|
||||
accepts("rootPrivateKeyPassword", "Password for the root certificate private key").withRequiredArg().describedAs("password")
|
||||
accepts("csrPrivateKeyPassword", "Password for the CSR signing certificate private key").withRequiredArg().describedAs("password")
|
||||
accepts("keyGenAuthThreshold", "Authentication strength threshold for the HSM key generation (default: $DEFAULT_KEY_GEN_AUTH_THRESHOLD)").withRequiredArg().ofType(Int::class.java).defaultsTo(DEFAULT_KEY_GEN_AUTH_THRESHOLD)
|
||||
accepts("signAuthThreshold", "Authentication strength threshold for the HSM CSR signing (default: $DEFAULT_SIGN_AUTH_THRESHOLD)").withRequiredArg().ofType(Int::class.java).defaultsTo(DEFAULT_SIGN_AUTH_THRESHOLD)
|
||||
accepts("authMode", "Authentication mode. Allowed values: ${AuthMode.values()} (default: $DEFAULT_AUTH_MODE)").withRequiredArg().defaultsTo(DEFAULT_AUTH_MODE.name)
|
||||
accepts("authKeyFilePath", "Key file path when authentication is based on a key file (i.e. authMode=${AuthMode.KEY_FILE.name})").withRequiredArg().describedAs("filepath")
|
||||
accepts("authKeyFilePass", "Key file password when authentication is based on a key file (i.e. authMode=${AuthMode.KEY_FILE.name})").withRequiredArg()
|
||||
accepts("authKeyFilePassword", "Key file password when authentication is based on a key file (i.e. authMode=${AuthMode.KEY_FILE.name})").withRequiredArg()
|
||||
accepts("autoUsername", "Username to be used for certificate signing (if not specified it will be prompted for input)").withRequiredArg()
|
||||
accepts("csrCertificateName", "Name of the certificate to be used by this CA to sign CSR (default: $DEFAULT_CSR_CERTIFICATE_NAME)").withRequiredArg().defaultsTo(DEFAULT_CSR_CERTIFICATE_NAME)
|
||||
accepts("rootCertificateName", "Name of the root certificate to be used by this CA (default: $DEFAULT_ROOT_CERTIFICATE_NAME)").withRequiredArg().defaultsTo(DEFAULT_ROOT_CERTIFICATE_NAME)
|
||||
accepts("validDays", "Validity duration in days (default: $DEFAULT_VALID_DAYS)").withRequiredArg().ofType(Int::class.java).defaultsTo(DEFAULT_VALID_DAYS)
|
||||
accepts("validDays", "Validity duration in days").withRequiredArg().ofType(Int::class.java)
|
||||
accepts("signInterval", "Time interval (in seconds) in which network map is signed (default: $DEFAULT_SIGN_INTERVAL)").withRequiredArg().ofType(Long::class.java).defaultsTo(DEFAULT_SIGN_INTERVAL)
|
||||
}
|
||||
|
||||
|
@ -24,20 +24,17 @@ class KeyCertificateGenerator(private val authenticator: Authenticator,
|
||||
/**
|
||||
* Generates root and intermediate key and certificates and stores them in the key store given by provider.
|
||||
* If the keys and certificates already exists they will be overwritten.
|
||||
* @param keyStorePassword password to the key store
|
||||
* @param certificateKeyName name of the intermediate key/certificate
|
||||
* @param privateKeyPassword password for the intermediate private key
|
||||
* @param intermediateCertificatesCredentials name and password for the intermediate key/certificate
|
||||
* @param parentCertificateName name of the parent key/certificate
|
||||
* @param parentPrivateKeyPassword password for the parent private key
|
||||
* @param validDays days of certificate validity
|
||||
*/
|
||||
fun generateAllCertificates(keyStorePassword: String? = null,
|
||||
intermediateCertificatesCredentials: List<CertificateNameAndPass>,
|
||||
fun generateAllCertificates(intermediateCertificatesCredentials: List<CertificateNameAndPass>,
|
||||
parentCertificateName: String,
|
||||
parentPrivateKeyPassword: String,
|
||||
validDays: Int) {
|
||||
authenticator.connectAndAuthenticate { provider, _ ->
|
||||
val keyStore = getAndInitializeKeyStore(provider, keyStorePassword)
|
||||
val keyStore = getAndInitializeKeyStore(provider)
|
||||
generateRootCertificate(provider, keyStore, parentCertificateName, parentPrivateKeyPassword, validDays)
|
||||
intermediateCertificatesCredentials.forEach {
|
||||
generateIntermediateCertificate(provider, keyStore, it.certificateName, it.privateKeyPassword, parentCertificateName, parentPrivateKeyPassword, validDays)
|
||||
|
@ -16,7 +16,6 @@ class HsmCsrSigner(private val storage: SignedCertificateRequestStorage,
|
||||
private val caPrivateKeyPass: String?,
|
||||
private val caParentCertificateName: String,
|
||||
private val validDays: Int,
|
||||
private val keyStorePassword: String?,
|
||||
private val authenticator: Authenticator) : CertificateSigningRequestSigner {
|
||||
|
||||
/**
|
||||
@ -31,7 +30,7 @@ class HsmCsrSigner(private val storage: SignedCertificateRequestStorage,
|
||||
*/
|
||||
override fun sign(toSign: List<ApprovedCertificateRequestData>) {
|
||||
authenticator.connectAndAuthenticate { provider, signers ->
|
||||
val keyStore = getAndInitializeKeyStore(provider, keyStorePassword)
|
||||
val keyStore = getAndInitializeKeyStore(provider)
|
||||
// This should be changed once we allow for more certificates in the chain. Preferably we should use
|
||||
// keyStore.getCertificateChain(String) and assume entire chain is stored in the HSM (depending on the support).
|
||||
val caParentCertificate = keyStore.getCertificate(caParentCertificateName)
|
||||
|
@ -7,7 +7,7 @@ import com.r3.corda.networkmanage.common.signer.SignatureAndCertPath
|
||||
import com.r3.corda.networkmanage.common.signer.Signer
|
||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||
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.utilities.loggerFor
|
||||
@ -26,7 +26,6 @@ import java.util.concurrent.TimeUnit
|
||||
class HsmNetworkMapSigner(networkMapStorage: NetworkMapStorage,
|
||||
private val caCertificateKeyName: String,
|
||||
private val caPrivateKeyPass: String,
|
||||
private val keyStorePassword: String?,
|
||||
private val authenticator: Authenticator,
|
||||
private val signingPeriod: Duration = DEFAULT_SIGNING_PERIOD_MS) : Signer {
|
||||
|
||||
@ -63,7 +62,7 @@ class HsmNetworkMapSigner(networkMapStorage: NetworkMapStorage,
|
||||
override fun sign(data: ByteArray): SignatureAndCertPath? {
|
||||
var result: SignatureAndCertPath? = null
|
||||
authenticator.connectAndAuthenticate { provider, _ ->
|
||||
val keyStore = X509Utilities.getAndInitializeKeyStore(provider, keyStorePassword)
|
||||
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)
|
||||
|
@ -237,14 +237,12 @@ object X509Utilities {
|
||||
|
||||
/**
|
||||
* Creates and initializes a key store from the given crypto server provider.
|
||||
* It uses the provided key store password to enable key store access.
|
||||
* @param provider crypto server provider to be used for the key store creation
|
||||
* @param keyStorePassword key store password to be used for key store access authentication
|
||||
* @return created key store instance
|
||||
*/
|
||||
fun getAndInitializeKeyStore(provider: CryptoServerProvider, keyStorePassword: String?): KeyStore {
|
||||
fun getAndInitializeKeyStore(provider: CryptoServerProvider): KeyStore {
|
||||
val keyStore = KeyStore.getInstance("CryptoServer", provider)
|
||||
keyStore.load(null, keyStorePassword?.toCharArray())
|
||||
keyStore.load(null, null)
|
||||
return keyStore
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,11 @@ device = "3001@127.0.0.1"
|
||||
keyGroup = "*"
|
||||
keySpecifier = -1
|
||||
authMode = PASSWORD
|
||||
csrPrivateKeyPassword = ""
|
||||
networkMapPrivateKeyPassword = ""
|
||||
rootPrivateKeyPassword = ""
|
||||
keyGroup = "DEV.DOORMAN"
|
||||
validDays = 3650
|
||||
|
||||
h2port = 0
|
||||
dataSourceProperties {
|
||||
|
@ -1,7 +1,12 @@
|
||||
device = "3001@127.0.0.1"
|
||||
keyGroup = "*"
|
||||
keyGroup = "DEV.DOORMAN"
|
||||
keySpecifier = -1
|
||||
authMode = PASSWORD
|
||||
csrPrivateKeyPassword = ""
|
||||
networkMapPrivateKeyPassword = ""
|
||||
rootPrivateKeyPassword = ""
|
||||
keyGroup = "DEV.DOORMAN"
|
||||
validDays = 3650
|
||||
|
||||
h2port = 0
|
||||
dataSourceProperties {
|
||||
|
@ -1,4 +1,8 @@
|
||||
device = "3001@127.0.0.1"
|
||||
keyGroup = "*"
|
||||
keyGroup = "DEV.DOORMAN"
|
||||
keySpecifier = -1
|
||||
authMode = PASSWORD
|
||||
authMode = PASSWORD
|
||||
csrPrivateKeyPassword = ""
|
||||
networkMapPrivateKeyPassword = ""
|
||||
rootPrivateKeyPassword = ""
|
||||
keyGroup = "DEV.DOORMAN"
|
Loading…
Reference in New Issue
Block a user