Canton KMS

We provide a driver that lets you use Builder Vault as an external key management service (KMS) for a Canton 3.5 participant node. This means that cryptographic keys such as namespace signing keys, protocol signing keys, and encryption keys will be protected by Builder Vault MPC.

As explained here, a Canton node can use an external KMS in two ways:

  • External keys The keys are fully protected by the external KMS. The keys are generated inside the KMS and never leave the KMS.
  • Enveloping Keys are generated by the Canton node and live unencrypted in the node's memory. Keys are protected at rest by enveloping (wrapping) performed by the external KMS.

The Builder Vault Canton KMS driver supports both modes of operation.

📘

We recommend external keys mode, since it provides stronger security. It also gives the best performance when running with Builder Vault Canton KMS.

While Canton 3.4 nodes can use AWS/GCP/Azure as external KMS, support for driver-based external KMS was first introduced in Canton 3.5. So Builder Vault only works with Canton 3.5 or later.

Canton NodeBuilder Vault KMS
Canton 3.5Builder Vault 73.3 LTS or later
Builder Vault Canton KMS driver v73.4.0
Builder Vault Canton KMS Admin Tool v73.4.0
Canton 3.4Not supported

External Keys with Builder Vault Canton KMS

Builder Vault Canton KMS supports the external keys mode of operation with the following cryptographic keys and algorithms. These are a subset of the schemes used in Canton. The last column in the tables below shows which MPC protocol must be enabled in the Builder Vault MPC node configuration in order to support the given key/algorithm.

Key SpecPurposeBuilder Vault MPC Configuration
EC-P256 [ec-p-256]Signing and encryption[DKLs23]
[SEPD20ECDH]
EC-P384 [ec-p-384]Signing[DKLs23]
EC-Secp256k1 [ec-secp-256k-1]Signing[DKLs23]
EC-Curve25519 [ec-curve-25519]Signing[SEPD19S]
RSA-2048Encryption[ADN06]
AlgorithmPurposeSupported Key SpecsBuilder Vault MPC Configuration
Ed25519 [ed-25519]SigningEC-Curve25519[SEPD19S]
EC-DSA-SHA256 [ec-dsa-sha-256]SigningEC-P256, EC-Secp256k1[DKLs23]
EC-DSA-SHA384 [ec-dsa-sha-384]SigningEC-P384[DKLs23]
ECIES-HMAC-SHA256-AES128-CBC [ecies-hkdf-hmac-sha-256-aes-128-cbc]EncryptionEC-P256[SEPD20ECDH]
RSA-OAEP-SHA256 [rsa-oaep-sha-256]EncryptionRSA-2048[ADN06]
📘

Builder Vault does not support generating RSA-2048 keys, but it can use RSA-OAEP-SHA256 for encryption if you import an RSA-2048 key. However, we recommend that if you use Builder Vault for external keys, that you configure your Canton participant node to use ECIES for encryption and rotate any existing RSA keys to ECIES keys.

Installation

👍

Testing with Canton LocalNet

The following explains how to install the Builder Vault Canton KMS in general.
Alternatively, you can follow the tutorial in our demo repository here. It show how to run a Canton participant node configured with Builder Vault KMS, all as local containers on your own machine.

You first need an instance of Builder Vault v73.3 LTS or later. For testing, you can deploy Builder Vault locally as explained here. Each MPC node in Builder Vault needs to be configured with API key authentication. See this for more on how to generate fresh API keys. It must also have the following features enabled:

[[Authentication.APIKeys]]
    # The API key that the Builder Vault Canton KMS driver will use to connect to this
    # MPC node. Use different API keys for each MPC node.
    APIKey = < Insert base64 encoded Builder Vault SDK API key here >
    ApplicationID = "canton-kms"

# Required for ECDSA signatures
[DKLS23.Features]
    GenerateKey = true
    Sign = true
    PublicKey = true
    ImportKey = true

# Required for Ed25519 signatures
[SEPD19S.Features]
    GenerateKey = true
    Sign = true
    PublicKey = true
    ImportKey = true

# Required for ECIES encryption
[SEPD20ECDH.Features]
    GenerateKey = true
    ComputeSecret = true
    PublicKey = true

The Canton artifacts can be downloaded the Blockdaemon repositories. Contact Blockdaemon to get the required Nexus credentials.

The Canton KMS driver can be included from the Sepior JNI Maven repository. This can be done in the Maven pom file with the following blocks:

    <repositories>
      <repository>
        <id>sepior-server</id>
        <url>https://nexus.sepior.net/repository/sepior-jni</url>
      </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>com.blockdaemon.bv</groupId>
            <artifactId>canton-kms-driver</artifactId>
            <version>73.4.0</version>
        </dependency>
    </dependencies>

The credentials can be defined in a settings.xml file that can be provided to the maven build with the -s option:

<settings>
    <servers>
        <server>
            <id>sepior-server</id>
            <username>${NEXUS_USER}</username>
            <password>${NEXUS_PASSWORD}</password>
        </server>
    </servers>
</settings>

In case the jar files are required, they can be downloaded using curl:

curl -u $NEXUS_USERNAME:$NEXUS_PASSWORD \
     -O https://nexus.sepior.net/repository/sepior-jni/com/blockdaemon/bv/canton-kms-driver/73.4.0/canton-kms-driver-73.4.0.jar \
     -O https://nexus.sepior.net/repository/sepior-jni/com/sepior/tsm/sdkv2/sdkv2/73.3.0/sdkv2-73.3.0.jar

The administration tool can be downloaded from the Sepior binary repository with the following command:

curl -u $NEXUS_USERNAME:$NEXUS_PASSWORD \
  -O https://nexus.sepior.net/repository/libtsmclient/canton-kms-admin-tool-73.4.0.zip

Then configure your Canton participant node to use the Builder Vault Canton KMS driver in external key mode. This may look like the following. (See the Canton docs for more driver-based KMS configuration.)

canton.participants.your-participant.crypto {
  provider = kms
  signing.keys.default = "ec-p-256"
  signing.algorithms.default = "ec-dsa-sha-256"
  encryption.keys.default = "ec-p-256"
  encryption.keys.algorithms.default = "ecies-hkdf-hmac-sha-256-aes-128-cbc"

  kms {
    type = driver
    name = "builder-vault-kms"
    config {

      # One entry per MPC node in Builder Vault.
      nodes = [
        { url = "https://bv-node-1:8000", api-key = "bv-node-1-api-key" }
        { url = "https://bv-node-2:8000", api-key = "bv-node-2-api-key" }
        { url = "https://bv-node-3:8000", api-key = "bv-node-3-api-key" }]
    }
  }
}

The above configuration assumes that your Builder Vault contains three MPC nodes, and that you want a security threshold of two. You can run with other configurations, for example with two MPC nodes and security threshold one.

Finally, run your Canton participant node with the above jar files on the classpath:

java \
  -cp canton-kms-driver-73.4.0.jar:sdkv2-73.3.0.jar:jna-5.13.0.jar:canton.jar \
  com.digitalasset.canton.CantonCommunityApp \
  -c canton.conf # further canton arguments

Builder Vault Java SDK requires jna-5.13.0.jar on the classpath as well. You can fetch this from the central Maven repository:

curl -O https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.13.0/jna-5.13.0.jar

Enveloping with Builder Vault Canton KMS

As an alternative to external keys mode, Builder Vault can be configured for enveloping mode as follows.

You first need an instance of Builder Vault v73.3 LTS or later and you need to fetch the Builder Vault Canton KMS driver and Builder Vault Java SDK jar files, as described in the previous section.

The only difference is that instead of [DKLs13], [SEPD19S], and [SEPD20ECDH], each MPC node in Builder Vault now needs to be configured with these features enabled:

[MRZ15.AESFeatures]
    GenerateKey = true
    GCMEncrypt = true
    GCMDecrypt = true
    ImportKey = true

And your Canton participant node must have this configuration:

canton.participants.your-participant.crypto {
    provider = jce
    private-key-store {
        encryption {
            type = kms
        }
    }
    kms { 
      # ... same as above 
    }
}

Then restart your Canton node as above, making sure to add the jars to the classpath:

java \
  -cp canton-kms-driver-73.4.0.jar:sdkv2-73.3.0.jar:jna-5.13.0.jar:canton.jar \
  com.digitalasset.canton.CantonCommunityApp \
  -c canton.conf # further canton arguments

The Canton node will then generate an AES-GCM key in Builder Vault and use that key to envelope its namespace, signing, and encryption keys.

Migration

We refer to the official Canton documentation for information about how to migrate your Canton node to or from Builder Vault Canton KMS. In summary:

  • External Keys Restarting your node with the external KMS enabled doesn't migrate your existing keys to the KMS. Only new keys will be generated in the KMS. To migrate existing keys to Builder Vault, you must set up a new participant with Builder Vault KMS enabled, then recreate parties and manually migrate DARs, contracts, etc., to the new participant.
  • Enveloping works more seamless. Just restart your node with Builder Vault configured for enveloping. Then the node will automatically envelope all existing keys, including the root namespace key. You can migrate in the reverse direction by restarting with this special flag set in the configuration: private-key-store.encryption.reverted = true. The node will then remove the enveloping.

Admin Tool

The KMS driver ships with an admin utility that lets you do operations directly in Builder Vault. You can for example use the utility tool to rotate an existing signing key in your Canton participant node to a signing key in Builder Vault:

$ java -jar canton-kms-admin-tool-73.4.0.jar \
    --config bv-admin.conf generate-key --key-id signing-v2 --type signing --curve p256

Then use the canton console to rotate to the external key:

val signingFingerprint = participant1.keys.secret.list()
    .find(_.publicKeyWithName.name.exists(_.unwrap == "signing"))
    .map(_.publicKeyWithName.publicKey.id.unwrap)
    .get
participant1.keys.secret.rotate_kms_node_key(
    fingerprint = signingFingerprint,
    newKmsKeyId = "signing-v2",
    name        = "signing"
)

You can use the admin tool to validate the fingerprint of the new signing key:

$ java -jar canton-kms-admin-tool-73.4.0.jar \
    --config bv-admin.conf get-public-key --key-id signing-v2 --format fingerprint
1220471744be672129c42e0c29ed898c712dd525cc8e3e62e2efbae57faf35c07986

Use --help for a full list of operations:

Builder Vault Admin CLI

Usage: java -jar canton-kms-admin-tool-<version>.jar [--config <file>] <command> [options]

Global options:
  --config <file>    HOCON config file (default: kms-admin-tool.conf)

Commands:
  generate-key       Generate a new key pair in Builder Vault
    --key-id <id>      Key ID (name) to assign in Builder Vault  [required]
    --type <type>      Key type: signing, encryption, symmetric   [required]
    --curve <curve>    Curve for signing/encryption keys          [default: p256]
                       signing:    p256, p384, secp256k1, ed25519
                       encryption: p256

  get-public-key     Export the public key for an existing key
    --key-id <id>      Key ID                                     [required]
    --format <fmt>     Output format: pem, der-hex, fingerprint   [default: pem]

  key-exists         Check whether a key exists in Builder Vault
    --key-id <id>      Key ID                                     [required]

  delete-key         Delete a key from Builder Vault
    --key-id <id>      Key ID                                     [required]

  import-key         Import an external private or symmetric key into Builder Vault
    --key-id <id>         Key ID to assign in Builder Vault        [required]
    --type <type>         Key type                                 [required]
                          p256, p384, secp256k1: ECDSA private key scalar via --private-key-hex
                          ed25519: private scalar via --private-key-hex, or RFC 8032 seed via --seed-hex
                          aes128:  128-bit AES key (16 bytes) via --key-hex
                          rsa: 2048-bit RSA key in PKCS #8 format via --private-key-hex
    --private-key-hex     Private key scalar as hex               [ECDSA; ed25519 raw scalar, RSA (PKCS #8)]
    --seed-hex            RFC 8032 seed as hex (derives scalar + pubkey internally) [ed25519]
    --key-hex             Raw AES key as hex                      [aes128]

Example: pre-create a rotation target for Canton key rotation:
  java -jar bv-admin.jar --config bv.conf generate-key \\
    --key-id signing-v2 --type signing --curve p256
Then in Canton:
  `app-provider`.topology.owner_to_key_mappings.rotate_key(...)

The bv-admin.conf is a configuration file containing the same as the "config" part in the "kms" section of the participant node. For example:

nodes = [
	{ url = "http://tsm-node-0", api-key = "apikey0" }
	{ url = "http://tsm-node-1", api-key = "apikey1" }
	{ url = "http://tsm-node-2", api-key = "apikey2" }
]