Configuring the ENM services to use SSL

The following components of the ENM suite can all be configured to encrypt their inter-process communication channels.

  • Identity Manager (containing previously named Doorman and Revocation services)
  • Network Map
  • Signing Service
  • Signable Material Retriever Service

This section explains how to configure the above components and the following diagram shows the flow of information between them.

enm with ssl

For SSL to work some PKI infrastructure must be in place. R3 recommends generating a self signed root key that can then be used to sign a key for each service. This way, all that needs distributing to the machines hosting the JVMs running the ENM components is a keystore containing the trust root (the Certificate representing the root key) and a keystore containing the keypair generated for that service.

The SSL handshake will, when one component talks to another, check that the exchanged keys have a certificate chain that chains back to the common root.

Thus the key signing hierarchy would be

  • Root
  • Identity Manager
  • Network Map
  • Revocation
  • Signing Service (including CSRs, CRRs, CRLs, Network Parameters, and the Network Map)

In general, ENM components are configured with SSL via the inclusion of an ssl configuration block containing keyStore and trustStore settings. You cannot enable SSL on the whole ENM suite at once. You must do it one by one on individual components. If you want two components to communicate with each other using SSL, you must enable SSL on both of them. When you enable SSL between two components, the connection between them is mutually authenticated. SSL enablement could be mixed within a single ENM deployment, with only a selected set of channels encrypted, but it will almost certainly be easier to roll it out as a whole.

Example: If you enable SSL on the server side, for example on the Identity Manager, then any client that will talk to that service must configure SSL for that communication stream.

All components should be configured to use SSL with the following configuration block. More details can be found in Identity Manager Configuration Parameters and Network Map Configuration Parameters.

ssl = {
    keyStore = {
        location = /path/to/keystore.jks
        password = <key store password>
        keyPassword = <key password>
    }
    trustStore = {
        location = /path/to/trustroot.jks
        password = <key store password>
    }
}

The keyStore contains the public and private keypair of the service signed by the root key.

The trustStore contains the root key’s certificate. This is, in effect, common across the entire ENM deployment as it is this that enables the various components to trust one another checking that the certificate presented chains back to this root certificate.

However, if the key and keystore passwords are the same, then the keyPassword option can be omitted.

ssl = {
    keyStore = {
        location = /path/to/keystore.jks
        password = <key store and key password>
    }
    trustStore = {
        location = /path/to/trustroot.jks
        password = <key store password>
    }
}

Finally, if the keystore contains the trustroot, then the trustStore can in turn be omitted.

ssl = {
    keyStore = {
        location = /path/to/keystore.jks
        password = <key store and key password>
    }
}

Those services that open ports for other ENM components to talk to can enable SSL by including the above settings within their enmListener configuration block:

enmListener {
    port = 5050
    ssl = {
        <<< As configured above >>>
    }
}

This will include the Network Map as well as both the Issuance and Revocation workflows inside the Identity Manager. Leaving these configuration blocks out of the respective config files will mean that each ENM listening server will be created without SSL and default to the following ports:

  • Network Map - 5050
  • Issuance (Identity Manager) - 5051
  • Revocation (Identity Manager) - 5052

Those ENM services which need to talk to other services as a client are configured similarly to the above, on a per-service basis. For example, the Network Map is configured to talk to the Identity Manager thusly:

networkMap = {
    ...
    identityManager = {
        host       = localhost
        port       = 5050
        ssl = {
            <<< As configured above >>>
        }
    }
    ...
}

When SSL is enabled on the Identity Manager it must be set here. This will cause any connections made to the Identity Manager to use the SSL credentials configured. Without these credentials, the Network Map side will attempt to initialise an unencrypted connection, whilst the Identity Manager will be expecting an initial SSL handshake to occur, resulting in an unsuccessful connection.

For some services, such as the Network Map, it is possible multiple SSL configuration blocks within the configuration file. It is considered to be most secure if each of these connections use a unique set of SSL keys, however in some situations it may be desirable to use the same SSL keys and certificates across multiple connections. To avoid repetition within the config files and improve readability the SSL configuration block can be extracted out to a separate file and then dynamically included within the config file. For example, the SSL settings below can be extracted to the file ssl-settings.conf:

ssl = {
    keyStore = {
        location = /path/to/keystore.jks
        password = <key store and key password>
    }
    trustStore = {
        location = /path/to/trustroot.jks
        password = <key store password>
    }
}

and then included in the Network Map config file thusly:

...
enmListener {
    port = 20001
    ssl = include "ssl-settings.conf"
}
...
identityManager = {
    host       = localhost
    port       = 5051
    ssl = include "ssl-settings.conf"
}
revocation = {
    host       = localhost
    port       = 5052
    ssl = include "ssl-settings.conf"
}

The following configuration files configure a small test deployment of the ENM suite of tools on a single machine. This is why all of the services are binding to localhost and can refer to a central location for the PKI and SSL certificates as well as the JAR files.

address = "localhost:10000"

database {
    driverClassName = org.h2.Driver
    url = "jdbc:h2:file:./identity-manager-persistence;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;WRITE_DELAY=0;AUTO_SERVER_PORT=0"
    user = "example-db-user"
    password = "example-db-password"
}

workflows {
    "issuance" = {
        type = ISSUANCE
        updateInterval = 1000
        enmListener {
            port = 5051
            reconnect = true
            ssl {
                keyStore {
                    location = exampleSslKeyStore.jks
                    password = "password"
                }
                trustStore {
                    location = exampleSslTrustStore.jks
                    password = "trustpass"
                }
            }
        }
        plugin {
            pluginClass = "com.r3.enmplugins.jira.JiraCsrWorkflowPlugin"
            config {
                address = "https://doorman-jira-host.r3.com/"
                projectCode = "CSR"
                username = "example-jira-username"
                password = "example-jira-password"
            }
        }
    },
    "revocation" = {
        type = REVOCATION
        enmListener {
            port = 5052
            reconnect = true
            # note that this SSL configuration could use different keys to the above if desired
            ssl {
                keyStore {
                    location = exampleSslKeyStore.jks
                    password = "password"
                }
                trustStore {
                    location = exampleSslTrustStore.jks
                    password = "trustpass"
                }
            }
        }
        plugin {
            pluginClass = "com.r3.enmplugins.jira.JiraCrrWorkflowPlugin"
            config {
                address = "https://doorman-jira-host.r3.com/"
                projectCode = "CRR"
                username = "example-jira-username"
                password = "example-jira-password"
            }
        }
        crlCacheTimeout = 2000
        crlFiles = ["./crl/root.crl", "./crl/subordinate.crl", "./crl-files/tls.crl"]
    }
}

shell {
    sshdPort = 10002
    user = "testuser"
    password = "example-password"
}
address = "localhost:20000"

database {
    driverClassName = org.h2.Driver
    url = "jdbc:h2:file:./network-map-persistence;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;WRITE_DELAY=0;AUTO_SERVER_PORT=0"
    user = "example-db-user"
    password = "example-db-password"
}

pollingInterval = 60000

enmListener {
    port = 5050
    reconnect = true
    ssl {
        keyStore {
            location = exampleSslKeyStore.jks
            password = "password"
        }
        trustStore {
            location = exampleSslTrustStore.jks
            password = "trustpass"
        }
    }
}

identityManager {
    host = "example-identity-manager-host"
    port = 5051
    reconnect = true
    # note that this SSL configuration could use different keys to the above if desired
    ssl {
        keyStore {
            location = exampleSslKeyStore.jks
            password = "password"
        }
        trustStore {
            location = exampleSslTrustStore.jks
            password = "trustpass"
        }
    }
}

revocation {
    host = "example-identity-manager-host"
    port = 5052
    reconnect = true
    # example revocation communication config without SSL
}

checkRevocation = true

shell {
    sshdPort = 20002
    user = "testuser"
    password = "example-password"
}
shell = {
  sshdPort = 20003
  user = "testuser"
  password = "example-password"
}

#############################
# Proprietary HSM libraries #
#############################
hsmLibraries = [
  {
    type = UTIMACO_HSM
    jars = ["/path/to/CryptoServerJCE.jar"]
  },
  {
    type = GEMALTO_HSM
    jars = ["/path/to/LunaProvider.jar"]
    sharedLibDir = "/path/to/shared-libraries/dir/"
  },
  {
    type = SECUROSYS_HSM
    jars = ["/path/to/primusX.jar"]
  },
  {
    type = AZURE_KEY_VAULT_HSM
    jars = ["/path/to/akvLibraries.jar"]
  },
  {
      type = AMAZON_CLOUD_HSM
      jars = ["/opt/cloudhsm/java/cloudhsm-3.0.0.jar"]
      sharedLibDir = "/opt/cloudhsm/lib"
  }
]

####################################################
# Optional default certificate store for any HSM   #
# signing keys without a certificate store defined #
####################################################
globalCertificateStore = {
  file = "exampleGlobalCertificateStore.jks"
  password = "example-password"
}

#############################################
# All individual keys used in signing tasks #
#############################################
signingKeys = {
    "CSRUtimacoHsmSigningKey" = {
        alias = "example-csr-key-alias"
        type = UTIMACO_HSM
        group = "example-hsm-group"
        specifier = 1
        keyStore {
            host = "192.168.0.1"
            port = "3001"
            users = [{
                mode = CARD_READER
            }]
        }
    },
    "CRLUtimacoHsmSigningKey" = {
        alias = "example-crl-key-alias"
        type = UTIMACO_HSM
        group = "example-hsm-group"
        specifier = 1
        keyStore {
            # Example using a different HSM to above key
            host = "192.168.0.2"
            port = "3002"
            # username and password omitted, user will be prompted during task execution
            users = [{
                mode = PASSWORD
            }]
        },
        # Using a unique, non-global certificateStore
        certificateStore = {
            file = "exampleCertificateStore.jks"
            password = "example-password"
        }
    },
    "NetworkMapUtimacoHsmSigningKey" = {
        alias = "example-map-key-alias"
        type = UTIMACO_HSM
        group = "example-hsm-group"
        specifier = 1
        keyStore {
            host = "192.168.0.1"
            port = "3001"
            users = [{
                mode = KEY_FILE
                keyFilePath = example-key-file
                password = "test-password"
            }]
        }
    },
    "NetworkParametersUtimacoHsmSigningKey" = {
        alias = "example-parameter-key-alias"
        type = UTIMACO_HSM
        group = "example-hsm-group"
        specifier = 1
        keyStore {
            host = "192.168.0.1"
            port = "3001"
            users = [{
                mode = CARD_READER
            }]
        }
    },
    "ExampleGemaltoHsmSigningKey" = {
        alias = "example-parameter-key-alias"
        type = GEMALTO_HSM
        credentials {
            keyStore = "tokenlabel:example-partition-name"
            password = "example-crypto-office-password" # this can be omitted and input at runtime
        }
    },
    "ExampleSecurosysHsmSigningKey" = {
        alias = "example-parameter-key-alias"
        type = SECUROSYS_HSM
        keyStore {
            host = "127.0.0.1"
            port = 1234
        }
        credentials = [{
            username = "example-username" # this can be omitted and input at runtime
            password = "example-password" # this can be omitted and input at runtime
        }]
    },
    "ExampleAzureKeyVaultHsmSigningKey" = {
        alias = "example-parameter-key-alias"
        type = AZURE_KEY_VAULT_HSM
        keyStore {
            keyVaultUrl = "http://example.com"
            protection = SOFTWARE
        }
        credentials {
            keyStorePath = "path/to/keystore"
            keyStorePassword = "example-password"
            keyStoreAlias = "example-alias"
            clientId = "12345-abcde-54321"
        }
    },
    "ExampleAwsCloudHsmSigningKey" = {
        alias = "example-parameter-key-alias"
        type = AMAZON_CLOUD_HSM
        credentialsAmazon {
            partition = "example-partition"
            userName = "example-user"
            password = "example-password"
        }
        localCertificateStore = {
            file = "exampleCertificateStore.jks"
            password = "password"
        }
    }
}

##########################################################
# All ENM service endpoints for fetching/persisting data #
##########################################################
caSmrLocation = {
    host = localhost
    port = 5010
    verbose = true
    # note that this SSL configuration could use different keys to the other locations if desired
    ssl {
        keyStore {
            location = exampleSslKeyStore.jks
            password = "password"
        }
        trustStore {
            location = exampleSslTrustStore.jks
            password = "trustpass"
        }
    }
}

nonCaSmrLocation = {
    host = localhost
    port = 5011
    verbose = true
    # note that this SSL configuration could use different keys to the other locations if desired
    ssl {
        keyStore {
            location = exampleSslKeyStore.jks
            password = "password"
        }
        trustStore {
            location = exampleSslTrustStore.jks
            password = "trustpass"
        }
    }
}

###################################################
# Signing tasks to be run (manually or scheduled) #
###################################################
signers = {
    "Example CSR Signer" = {
        type = CSR
        signingKeyAlias = "CSRUtimacoHsmSigningKey"
        crlDistributionPoint = "http://localhost:10000/certificate-revocation-list/doorman"
        validDays = 7300 # 20 year certificate expiry
    },
    "Example CRL Signer" = {
        type = CRL
        signingKeyAlias = "CRLUtimacoHsmSigningKey"
        crlDistributionPoint = "http://localhost:10000/certificate-revocation-list/doorman"
        updatePeriod = 5184000000 # 60 day CRL expiry
    },
    "Example Network Map Signer" = {
        type = NETWORK_MAP
        signingKeyAlias = "NetworkMapUtimacoHsmSigningKey"
        schedule {
            interval = 1minute
        }
    },
    "Example Network Parameter Signer" = {
        type = NETWORK_PARAMETERS
        signingKeyAlias = "NetworkParametersUtimacoHsmSigningKey"
    }
}

Was this page helpful?

Thanks for your feedback!

Chat with us

Chat with us on our #docs channel on slack. You can also join a lot of other slack channels there and have access to 1-on-1 communication with members of the R3 team and the online community.

Propose documentation improvements directly

Help us to improve the docs by contributing directly. It's simple - just fork this repository and raise a PR of your own - R3's Technical Writers will review it and apply the relevant suggestions.

We're sorry this page wasn't helpful. Let us know how we can make it better!

Chat with us

Chat with us on our #docs channel on slack. You can also join a lot of other slack channels there and have access to 1-on-1 communication with members of the R3 team and the online community.

Create an issue

Create a new GitHub issue in this repository - submit technical feedback, draw attention to a potential documentation bug, or share ideas for improvement and general feedback.

Propose documentation improvements directly

Help us to improve the docs by contributing directly. It's simple - just fork this repository and raise a PR of your own - R3's Technical Writers will review it and apply the relevant suggestions.