Onboarding
When your Fireblocks workspace is created, the workspace Owner receives an email to begin onboarding. Select the link inside the email and follow the steps to join the workspace with the Fireblocks Mobile app (the minimum supported version is 2.7.0).
Set up the Fireblocks Agent
Once you have successfully onboarded to your workspace, you can set up the Fireblocks Agent that connects to your workspace.
Fireblocks Agent is an open-source on-prem service (TypeScript) responsible for receiving new messages to sign from Fireblocks, relaying these messages to the customer’s HSM through the customer’s server, and returning the signed results to Fireblocks.
The below describes how to set up your Fireblocks Agent.
- Install the Fireblocks Agent: Follow the instructions here to install the Fireblocks Agent on the appropriate machine. Run the agent and ensure it's connected to either the example server in the same repository or your actual server. The agent will prompt you to enter a pairing token, which you will obtain in the next step.
- Create an API User: From your Console, create an API user with the Signer role by following the steps in this article. After the Admin Quorum approves the API user, retrieve its pairing token from the Fireblocks Console.
- Pair the API User: Use the pairing token you retrieved and enter it in the Console where the Fireblocks Agent prompted to pair the API user with the agent.
Re-enrolling an API user
In your Fireblocks Console, follow these steps:
- Go to Settings > Users tab.
- Find the API user you want to re-enroll, select More Actions (...) > Re-enroll API user.
A request is submitted to the workspace Owner to approve re-enrolling the API user. After the Owner approves the request, you will get a new pairing token for the user in the Console. Use the pairing token you retrieved and enter it in the Console where the Fireblocks Agent prompted to pair the API user with the agent.
Add your keys
Currently, adding keys is only supported via the Fireblocks Rest API. Before you can add your keys, you must create an API user with the Editor, Admin, or Signer role. Then you can use the Rest API or one of the SDKs (Python, JS, Java) to add your keys. You will also need to configure your Transaction Authorization Policy (TAP) rule to set a designated signer.
In your Key Link enabled Fireblocks workspace, two types of keys managed by your organization are used: Validation Key and Signing Key.
Validation Keys
A validation key is used as proof of authority for the approvals when adding new signing keys to your workspace. This allows a more automated and seamless way of registering and approving new signing keys without needing to approve them manually. Before adding a signing key, the key must be signed by an active validation key previously registered to your workspace, and Fireblocks must verify the signature’s validity.
Before adding a new validation key, you should edit your approval group for registering validation keys. In your Fireblocks Console, go to Settings > Quorums tab > Security & compliance > Add validation keys. You can learn more about the Approval groups feature here.
Use the `POST /v1/key_link/validation_keys` API endpoint to add a new validation key.
After adding a new validation key, your approval group quorum must approve it using the Fireblocks mobile app. Upon approval, you can register new signing keys.
Signing Keys
Signing keys are individual keys you manage on your HSM or other FIPS-compliant devices with which you can create wallets on Fireblocks. The signing requests will be sent to your device via the Fireblocks Agent. Fireblocks currently supports external registration for ECDSA and EdDSA keys. Before adding signing keys to your Fireblocks workspace you must choose the proof of ownership method, described below. This process can be performed either interactively or non-interactively.
Interactive Proof of Ownership
In the interactive proof of ownership method, the signing key is added without any proof attached to the request. Once added to your workspace, Fireblocks sends a challenge through the Fireblocks Agent. The HSM must sign this challenge for the specific key being added. The Agent then relays the signature back to Fireblocks where it is verified. Once verification is complete, the signing key is enabled.
Note
Using this method, the Proof of Ownership message to be signed is computed as sha256({tenant_id}-{request_id}-{key_id}).hexdigest()
. To verify the message's integrity, you can reconstruct the raw bytes from the request parameters, compute their hash, and then compare it with the hash included in the request. This ensures that you are signing the correct message, as shown below:
tenant_id = msg["tenantId"]
request_id = msg["requestId"]
key_id = msg["keyId"]
expected_data_to_sign = f'{tenant_id}-{request_id}-{key_id}'.encode()
data_to_sign = msg["messagesToSign"][0]["message"]
assert data_to_sign == sha256(expected_data_to_sign).hexdigest()
Non-interactive Proof of Ownership
In the non-interactive proof of ownership method, the signing key is added with both a proof of ownership message and a signature attached to the request. These elements are included in the `proofOfOwnership` object within the request body, which contains a message and a signature parameter. The expected message format is:
`Fireblocks|Proof of Ownership Message|<WorkspaceDisplayName>|<SdkApiKey>|<signingDeviceKeyId>|UnixTimeInSeconds`
This message should be in hexadecimal format and is designed to avoid accidental signatures. The components of the message are as follows:
- `Fireblocks`: A constant string.
- `Proof of Ownership Message`: A constant string.
- `<WorkspaceDisplayName>`: The name of your workspace, preventing mix-ups across workspaces.
- `<SdkApiKey>`: A GUID representing the API key making the request.
- `<signingDeviceKeyId>`: The ID or label of the signing key in the HSM.
- `UnixTimeInSeconds`: The timestamp reflecting the time of signature creation.
After creating the message and hashing it with SHA256, the HSM should sign the hash. Both the message (in hexadecimal format) and the signature must be included in the request body when adding a signing key. Signing keys added with the `proofOfOwnership` object will not receive an interactive proof of ownership challenge. If the signature is valid, the signing key will be enabled immediately.
Once you decide which proof of ownership method you will use, you can create and add your signing keys:
- Create a key pair using one of the supported algorithms in your Key Management Infrastructure and get its public key.
- Create a signed certificate from this public key using an active validation key. The script example below creates certificates that include a public signing key signed by a validation key.
#!/usr/bin/env python3 import argparse # Declare signing key wrapper function from datetime import datetime, timedelta, timezone from cryptography import x509 from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ed25519 from cryptography.hazmat.primitives.serialization import (load_pem_private_key, load_pem_public_key) from cryptography.x509.oid import NameOID def issue_certificate(root_ca_private_key, certificate_pubkey, common_name, issuer_name) - x509.Certificate: # For Ed25519, only the Ed25519 signature algorithm is used sign_algo = None if isinstance(root_ca_private_key, ed25519.Ed25519PrivateKey) else hashes.SHA256() now = datetime.now(timezone.utc) time_delta = timedelta(minutes=5) certificate = x509.CertificateBuilder().subject_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, common_name), ]) ).issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, issuer_name), ]) ).public_key( certificate_pubkey ).serial_number( x509.random_serial_number() ).not_valid_before( now ).not_valid_after( now + time_delta ).add_extension( x509.AuthorityKeyIdentifier.from_issuer_public_key( root_ca_private_key.public_key() ), critical=False ).sign(root_ca_private_key, sign_algo) return certificate def wrap_external_key(validator_privkey, external_public): COMMON_NAME = "ExampleName" ISSUER_NAME = "ExampleIssuerName" cert = issue_certificate(validator_privkey, external_public, COMMON_NAME, ISSUER_NAME) return cert.public_bytes(encoding=serialization.Encoding.PEM).decode() # Wrap singing key with validation key encoded_sign_pub_key = load_pem_public_key(sign_pub_key.encode()) signed_key_cert_pem = wrap_external_key(val_priv, encoded_sign_pub_key) print(signed_key_cert_pem)
- Once you have the signed certificate, upload it to Fireblocks via the `POST /v1/key_link/signing_keys` API endpoint. Note that when you add a new signing key, you must specify the ID of the relevant Fireblocks Agent user you created. This ensures that the relevant Fireblocks Agent receives the signing requests for this key.
- You can check its status through the `GET /v1/key_link/signing_keys/{keyId}` API endpoint.
- Once the certificate is verified, your key will be successfully registered to your workspace. Note that at this stage your signing keys will be set to `enabled=false`.
- If you have chosen the interactive proof of ownership method, your signing keys will be set to `enabled=false`. You must still complete the remaining steps below to create wallets.
- Fireblocks will then send a Proof of Ownership signing request to your Fireblocks Agent, which should be signed by your HSM.
- Once the message is signed, sent back, and verified by Fireblocks, your signing keys will be set as enabled.
- If you have chosen the non-interactive proof of ownership method, and the message and signature you attached to the request are valid, the key will be enabled.
- You can now assign your key to vault accounts and create wallets within.
Once you have successfully registered a signing key, you can continue to the next steps: configuring a TAP rule and setting up your Vault. Before you continue, you can add as many keys as you need to your workspace.
Configure a TAP rule
To configure the TAP rule, you must first create an API user with a Signer role for the Fireblocks agent as described here. You can create many different TAP rules for your workspace needs and learn more about them in this article. For each TAP rule, you must ensure the designated signer is set to the API user you created for the Fireblocks Agent.
Learn how to Set up your Fireblocks Vault with Key Link.