Signing for approval
In this article
By the end of this document you should have:
- A basic understanding of how to sign & approve requests in Taurus-PROTECT.
- How signatures are used to ensure authenticity of approvals.
- The importance of private keys and keeping them secure.
- How to programmatically sign a request.
Introduction
Many actions within Taurus-PROTECT are subject to governance rules that require digital signatures from designated operators in groups. Therefore, it is critical to ensure that every approval is genuine, traceable, and tamper-proof.
A digital signature allows an approver to sign a request in a way that:
- Verifies the identity of the signer.
- Guarantees the integrity of the signed data.
- Prevents the signer from denying their approval (non-repudiation).
This document explains how Taurus-PROTECT utilizes digital signatures for approvals, how those signatures are used to confirm authenticity, and the management of these keys. Later, you'll also learn how to programmatically sign a request using standard tools and libraries.
User key management
Public and private keys can be assigned to users using the Taurus UI. For more information, please see the relevant section in the User Guide .
When is a signature required?
Several of Taurus Protect APIs include a signature parameter. The most important ones to consider are the following:
Approving a transaction request
Approving a whitelisted contract
Approving a whitelisted address
What do I need to have in order to sign a request?
Warning
A user in protect can only have one signing method enabled. This could be one of the following. Signing methods are mutually exclusive. Please ensure this is thoroughly understood prior to changing the public key field for any user in Taurus-PROTECT.
Signing Method | Web | Desktop | API | Additional Information |
---|---|---|---|---|
Key Container | β | β | β | This is the default method that protect ships with. It is quite long and required to be entered at login. To simplify use, Protect can save the encrypted Key Container and a passcode can be used to unlock the Key Container for signing. |
Mobile App | β | β | β | SeeSigning with Taurus Sign for more information. |
Yubikey | β | β | β | Used in the desktop app only. Once set, user can no longer sign via web app. |
Openssl EC Private Key | β | β | β | Used exclusively sign via API. A daemon or service account user should be created on behalf of your application. Once Open SSL keys are set, that user can only sign via API. Once keys are set, all other signing become unavailable. You will no longer be able to login to the web or desktop apps once this key type has been set. |
Using the Taurus Protect UI, signatures are done through Key Containers, which carry an encrypted private key, accessed through a "passphrase". This is distinct from a "password", which is required for login. Alternative key storage mechanisms for interactive use include Yubikeys or the Taurus Mobile app.
The remainder of this document will discuss signing via API. Please ensure the user you are using to sign programatically does not require the ability to sign requests any other way.
To sign requests programmatically, you will need to make sure you have the following prepared:
- Access to an unencrypted ECDSA private key which is set up for the API user as described in the User Guide
- You must have the correct roles assigned to your API user. These roles are enforced for each API call, such as
RequestApprover
,WhitelistedAddressApprover
, etc. You can read more about roles in the User Management section in our guides. - A user that is a member of the respective signature group based on the transaction rules configured in Protect. For more information on this, see Transaction Rulesin our guides.
Roles
The roles required are listed in the API documentation on each approval endpoint. If you do not have the right permissions, you will need to contact your admin.
Generate a new key
To generate a keypair that you can use to sign transactions programmatically, we recommend using the commonly available openssl
tool.
First, you need to generate an ECDSA private key on the P256 NIST curve:
openssl ecparam -out ./[email protected] -name prime256v1 -genkey
Next, you must derive the corresponding public key from the private key:
openssl ec -in ./[email protected] -pubout -out ./[email protected]
Configure your user
A Protect Administrator will need to set or change thePublic Key
entry for the API user account and ensure the user is assigned to the correct approval group. Finally, another Administrator and a Superadmin must approve both, the account's group memberships and the public key.
Keep your private key secure
For production workloads, we recommend storing your private key in a secrets manager such as Vault, or KMS. Avoid storing unencrypted private keys in version control systems!
Signing Requests
Prepare the payload
Before applying the signature scheme, we must prepare the payload to be signed.
A single signature can cover multiple requests of the same kind, as each request kind will have its own numeric IDs that can overlap. To retrieve the necessary information for producing the signatures, you can use eg. the following endpoints:
- List whitelisted addresses for approval
- List whitelisted contracts for approval
- List requests for approval
These endpoints return with the same pattern in their responses. To produce a valid signature, we require 2 pieces of data from the response JSON structure: the id
of the item and the metadata.hash
property.
{
"result": [
{
"id": "442",
...
"metadata": {
"hash": "fda859afd5dcc16f7abec8e7ab7fc528d90b094e43eeb111037581c45f8e16b5",
...
}
...
}
]
}
Always validate before you sign
While this document is focusing on producing a correct signature that's accepted by Taurus-PROTECT, for brevity we omit important steps to verify the data we sign.
For production workloads, ensure you validate and verify the contents of what is being signed and ensure it is correct.
Now that all necessary data is retrieved, 2 different structures must be prepared for a successful signature of requests:
- The numerically sorted list of IDs that are being signed off on
- The list of
metadata.hash
values for each request, numerically sorted by the corresponding IDs.
To make this practical, look at the following python code snippet:
sorted_results = sorted(response.result, key=lambda x: int(x['id']))
ids = [str(request.id) for request in sorted_results]
payload = json.dumps([request.metadata.hash for request in sorted_results])
# payload: ["fda859afd5dcc16f7abec8e7ab7fc528d90b094e43eeb111037581c45f8e16b5"]
The payload
variable is required for the ECDSA-SHA256 signature below, while the ids
variable is required to create the API call which also contains the final signature for approval.
Creating the ECDSA-SHA256 signature
Using the ECDSA-SHA256 signature scheme to produce a signature in the format Taurus-PROTECT expects requires the following steps:
- Signing the
payload
variable using the ECDSA private key and SHA256 hash function. - Base64 encode the binary signature.
Putting these together into a code snippet, it will look something like below:
payload='["fda859afd5dcc16f7abec8e7ab7fc528d90b094e43eeb111037581c45f8e16b5"]'
echo -n "$payload" | openssl dgst -sha256 -sign your-private.key | openssl asn1parse -inform DER
# 0:d=0 hl=2 l= 68 cons: SEQUENCE
# 2:d=1 hl=2 l= 32 prim: INTEGER :234C56C972372F7DC331900ABEF2979E5583DC61975A1D00B8BE731C3D760C6A
# 36:d=1 hl=2 l= 32 prim: INTEGER :76FE947687631B822419ACD181DBBB3F881F77F1480C2B5C5485B9B57CDC7C9F
echo -n "234C56C972372F7DC331900ABEF2979E5583DC61975A1D00B8BE731C3D760C6A76FE947687631B822419ACD181DBBB3F881F77F1480C2B5C5485B9B57CDC7C9F" | xxd -p -r | base64 | tr -d '\n'
# The outputed signature, base64 encoded.
#I0xWyXI3L33DMZAKvvKXnlWD3GGXWh0AuL5zHD12DGp2/pR2h2MbgiQZrNGB27s/iB938UgMK1xUhbm1fNx8nw==
Code Examples
Taurus customer support is able to provide more full fledged code examples upon request. The snippets above are intended for demonstration only. They are not complete and will not work on their own without additional library imports and supporting code.
Submitting the signature
After creating a request and listing pending items for approval, submitting the approval and the corresponding signature also has its own endpoint for each kind of request you can make:
Approvals all use the same JSON schema for the POST
request:
{
"comment": "mandatory comment to describe the action",
"ids": ["1234", "2345"],
"signature": "I0xWyXI3L33DMZAKvvKXnlWD3GGXWh0AuL5zHD12DGp2/pR2h2MbgiQZrNGB27s/iB938UgMK1xUhbm1fNx8nw=="
}
At this point, all data should be available for creating the API call:
- Comment is a free-form field, and typically you will want to use some internal reference or verifiable information that corresponds to the approval
- We prepared the
ids
sorted list in the "Prepare the Payload" section above. - The
signature
field is the Base64 encoded signature created in the previous section.
Congratulations! You have successfully approved some requests in Taurus-PROTECT!
Complete examples
To see some complete workflow examples, please see the following pages:
- Whitelisting: How to whitelist addresses and contracts
- Transactions: How to create a transaction
Updated 8 days ago