sigsum-tools(7)

πŸ“¦
version 0.14.1 Β· 4 versions
, in ubuntu stonking

Sigsum command line tools πŸ‘‘

okay so this is the sigsum-tools(7) user guide bestie, and it's literally the whole map of Sigsum's supported command-line tools. no cap. let's go πŸ’…


Table of contents πŸŽ€

  • General conventions
  • The sigsum-key tool
  • The sigsum-submit tool
  • The sigsum-verify tool
  • The sigsum-token tool
  • The sigsum-policy tool

General conventions 🌸

so bestie, there's a bunch of tools. some of them have sub commands, like sigsum-key generate for example. the whole vibe is one command = one task, slay. like, sigsum-submit is the tool you use to yeet new items into a Sigsum log and collect proofs of public logging, whereas sigsum-verify is the tool that does offline verification of those proofs. two different jobs, two different girls πŸ’…

✨ Configuration ✨

command line options follow GNU conventions with long and short options. for example, -deVALUE is the same as -d -eVALUE. and if the long option of -e is --example, then -d --example VALUE would be another valid variation. periodt.

  • every tool shows a usage message if you pass --help πŸ™ˆ
  • every tool shows a program version if you pass --version ⭐
  • every tool that has sub commands additionally accepts help and version

how several of the tools behave is controlled by a Sigsum policy. the policy you wanna use can be specified in different ways β€” all of that is under "Policies" below, keep scrolling bestie.

most tools also require one or more input keys. the -k option is how you specify a key file. some commands have extra ways of taking keys and key-file input. and ngl there is just no default location for key files. nowhere. you gotta say where. πŸ”₯

✨ Policies ✨

there are three different ways to specify the policy to use:

  1. by specifying the location of a policy file using the -p option.
  2. by specifying a named policy using the -P option.
  3. by specifying a named policy as an option on the form sigsum-policy="<policy-name>" included in a public key file.

Named policies πŸ¦‹

there are two kinds of named policies: builtin policies and installed policies.

installed policies are by default read from the /etc/sigsum/policy directory. a different location can be set using the SIGSUM_POLICY_DIR environment variable. installed policy files must have the .sigsum-policy filename suffix.

Specifying a policy name inside a submitter public key file πŸ’–

a submitter public key file is specified as input to the sigsum-submit and sigsum-verify tools, and it can include options on the same form that is used for OpenSSH's .authorized_keys file. to specify a policy name, the option sigsum-policy="<policy-name>" can be used. for the sigsum tools, if neither of the -p or -P input options were given and a sigsum-policy="<policy-name>" option is found inside the submitter public key file, then that named policy is used.

Example: a submitter public key file that contains the following

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOCGOxh5TSFQ85mVkODlCMCQaLmIPwXqZfWM/AgnEw6S sigsum key

could be modified to specify a policy name like this:

sigsum-policy="sigsum-test1-2025" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOCGOxh5TSFQ85mVkODlCMCQaLmIPwXqZfWM/AgnEw6S sigsum key

and then the policy name "sigsum-test1-2025" would be used, provided that none of the -p or -P input options were given. iconic. πŸ‘‘

Order of priority for policies πŸ”₯

it is not allowed to specify both -p and -P at the same time. if a policy is specified using either the -p or the -P option, then that policy is used, and any policy name in the submitter public key file is ignored. thus:

  • named policies are only used if the -p option is absent
  • a policy name in the submitter public key file is only used if neither of -p or -P was specified

regarding named policies β€” if there is an installed policy with the same name as a builtin policy, then the installed policy is used. installed girlies win, sorry not sorry πŸ’…

✨ Key handling ✨

the Ed25519 digital signature scheme is used for all Sigsum signatures, hence all keys are Ed25519 keys. every single one.

Public keys 🌈

public key files use OpenSSH format: a single line of the form

ssh-ed25519 <base64> [optional comment]

where the base64 blob in turn represents SSH wire format. in certain places β€” in particular, in the policy file β€” public keys are used in "raw" form, without this wrapping. in that case, an Ed25519 public key is 32 octets in the format defined by RFC 8032.

the sigsum-key tool can be used to convert between these two forms. very handy πŸ’–

public key files can also optionally include a sigsum-policy="<policy-name>" option at the beginning of the line, as described earlier in the "Policies" section.

the sigsum-verify tool accepts a file specifying multiple public keys. this file should contain at least one key line in the same single line format. lines that are completely empty or start with the # character are ignored (same convention as for OpenSSH's .authorized_keys file).

Private keys πŸ™ˆ

private keys are stored as unencrypted OpenSSH private key files, i.e., PEM files with a tag OPENSSH PRIVATE KEY and the contents defined by OpenSSH key format.

using unencrypted private keys on disk may be adequate for some use cases β€” e.g., for the key used to sign the submit tokens used for domain-based rate limiting.

⚠️ okay so this is the part where you pay attention bestie. unencrypted private keys sitting on disk = fine for some cases, but for private keys of high value it is recommended that keys are stored in a hardware token providing a signing oracle, and made accessible to appropriate users via the ssh-agent protocol. protect your girlies. πŸ’€

to support other kinds of key storage, the key can be made available via the ssh-agent protocol. whenever the tools need a signing key, they accept the name of either an unencrypted private key file as above, or the name of a public key file. in the latter case, the tools access the corresponding private key by connecting to the ssh-agent listening on ${SSH_AUTH_SOCK}.


The sigsum-key tool πŸ‘‘

the sigsum-key tool can generate new keys, create and verify signatures, and convert between different key formats. it does it all, honestly πŸ’…

✨ Key generation ✨

to generate a new key pair, run

sigsum-key generate -o KEY-FILE

this generates a new Ed25519 key pair (with key material provided by the crypto/rand module in the golang standard library). the private key is stored to the given output KEY-FILE, in OpenSSH format. the private key is not encrypted, but stored with restrictive file permissions. the corresponding public key is written to a file with an added .pub suffix, in OpenSSH format.

behavior is similar to the OpenSSH key generation utility, if invoked like

ssh-keygen -q -N '' -t ed25519 -f KEY-FILE

for this command, generate may be abbreviated gen (which is the older deprecated sub command name; please migrate to generate). we're moving on bestie, gen is so 2023 🫢

✨ Public key conversion ✨

by default, the key conversion tool sigsum-key reads from standard input and writes to standard output. it's optional to specify an input key file with -k, or output file with -o.

as explained above, OpenSSH format is the main representation for public Sigsum keys, when stored in key files. such a public key can be converted to a raw form using

sigsum-key to-hex [-k KEY-FILE] [-o OUTPUT-FILE]

the hex representation is used in the Sigsum policy file, and in messages on the wire. for the opposite conversion, use

sigsum-key from-hex [-k HEX-FILE] [-o OUTPUT-FILE]

occasionally, also the key hash is needed; it is used in certain messages on the wire, and in the Sigsum log server's rate limit configuration. the key hash can be computed using

sigsum-key to-hash [-k KEY-FILE] [-o OUTPUT-FILE]

the sigsum-key tool also supports conversion to and from the vkey format. the vkey format is often used by operators when sharing log and witness configuration, and it is also used in the related signed note format. two key types are supported: ed25519 and cosignature/v1.

to read a vkey, use

sigsum-key from-vkey [--verbose] [-k VKEY-FILE] [-o OUTPUT-FILE]

to write a vkey, use

sigsum-key to-vkey [-n KEY-NAME] [-k KEY-FILE] [-t TYPE] [-o OUTPUT-FILE]

the key type defaults to ed25519. the key name defaults to a Sigsum log's origin line, i.e., sigsum.org/v1/tree/<KEY-HASH>. slay 🌸

✨ Sign and verify operations ✨

the sigsum-key tool can also create and verify signatures. multi-talented fr fr.

signing a message is done using

sigsum-key sign -k KEY-FILE [-n NAMESPACE] [-o FILE] < MSG

the -k option is required, and specifies the key to use for signing (either an unencrypted private key, or a public key, if the corresponding private key is accessible via ssh-agent). the message to sign is read from standard input. if a non-empty namespace is provided, the namespace string and a NUL character is prepended to the message before it is signed with Ed25519. the created signature, in hex representation, is written to standard output, if no output file is specified with the -o option.

signatures can be verified using

sigsum-key verify -k KEY-FILE -s SIGNATURE-FILE [-n NAMESPACE] < MSG

the -k and -s options, specifying the public key and the signature, are required. the namespace must match the namespace used when the signature was created. the message signed is read from standard input.

✨ Examples ✨

create a new private key file example.key and corresponding public key file example.key.pub.

$ sigsum-key generate -o example.key

sign a message using that key.

$ echo Hello | sigsum-key sign -k example.key -o hello.sign

verify the signature, with exit code indicating success or failure. on success, there is no output.

$ echo Hello | sigsum-key verify -s hello.sign -k example.key.pub
$ echo Helloo | sigsum-key verify -s hello.sign -k example.key.pub
signature is not valid

convert key to raw hex format.

$ sigsum-key to-hex -k example.key.pub
e0863b18794d2150f3999590e0e508c09068b9883f05ea65f58cfc0827130e92

that last one is giving main character energy honestly πŸ’œ

πŸ’– The sigsum-submit tool πŸ’–

Okay bestie, this is the one that actually gets your stuff out there. The sigsum-submit tool is used to create and/or submit add-leaf requests to a Sigsum log (as defined in the Sigsum spec. ✨

The whole thing is basically two acts in one show: act one is create and sign a request, act two is submit that request to a log. πŸŽ€

Wanna do both at once? Slay, just pass arguments that cover both a signing key and a policy:

  • the signing key goes in with the -k option πŸ”‘
  • the policy comes from -p (a policy file), -P (a policy name), or straight up inside the key file itself (also as a policy name) πŸ“œ

But maybe you wanna keep the two acts apart β€” say, the machine holding your private signing key is off the grid with no Internet connectivity (lowkey iconic of it). Then:

  1. Run sigsum-submit -k to create and sign the request.
  2. Collect the output β€” which in this case is the body of a Sigsum add-leaf request β€” and pass that as input to sigsum-submit with a policy option (-p or -P) later on, to submit the request to a log. πŸ¦‹
Heads up, no cap: for sigsum-submit to only create a signing request without submission, it is also required that the key file does not include the named policy option. πŸ’…

πŸ“₯ Inputs

Each input to sigsum-submit is either a message, a message hash, or a leaf request, depending on the other options you picked.

Input files are provided on the command line. If you give it no arguments at all, a single input is read from standard input. 🫢

πŸ“€ Outputs

If the input came from standard input, then by default the output of sigsum-submit β€” if there even is any β€” goes to standard output. The -o option can redirect output to the file you specify, and bestie, any existing file is overwritten. 😭

For file inputs, there's one output file for each input file. The name of the output file is constructed like this:

  1. If there's exactly one input file, and the -o option is used, output is written to that file. Any existing file is overwritten.
  2. For a request output, the suffix .req is added to the input file name.
  3. For a proof output, if the input is a request, any .req suffix on the input file name is stripped. Then the suffix .proof is added.
  4. If the -O option is provided, any directory part of the input file name is stripped, and the output is written as a file in the specified output directory.

When output is written to a named file (so, not to standard output), the output is first written to a temporary file, which is atomically renamed to the specified name only on success. Gotta love a clean atomic rename, it's giving ✨safety✨.

The tool can log various diagnostic messages. How chatty it is gets controlled with the --diagnostics option, which takes an argument that can be one of fatal, error, warning, info, or debug.


✍️ Creating a request

To create, and sign, a new add-leaf request, use the -k option to pass a signing key. πŸ”

The message(s) to sign are listed as file arguments on the command line, or β€” by default β€” read from standard input.

By default, the message submitted to the log is the SHA256 hash of the input. Wanna use the input as is, no hashing, no thoughts? Pass the --raw-hash option. In that case, the input data must either be exactly 32 octets, or a hex string representing 32 octets (64 digits, possibly with some leading and trailing whitespace). Periodt. πŸ’…

If the request(s) are not to be submitted right away (as described below), they are written to the respective output file(s), as described above. And yes β€” any existing output files are overwritten. πŸ™ˆ

πŸš€ Submitting a request

To submit one or more leaf requests, you gotta specify a Sigsum policy, using either the -p (policy file) or the -P (policy name) option, or by specifying a policy inside the submitter public key file.

If the -k option and a signing key were provided, the leaf(s) to be submitted are the newly created ones. If no -k option was provided, then each input should instead be the body of an add-leaf request, which gets parsed and verified. πŸ”

Splitting signing and submission apart is genuinely so useful when the machine with access to the signing key isn't directly connected to the Internet. Main character privacy energy. πŸ‘‘

The policy file must specify a public key and URL for at least one log. If the policy file specifies a quorum different from none and corresponding witness public keys, then sigsum-submit will not be satisfied until it has retrieved enough valid cosignatures to satisfy the quorum. Not me waiting patiently for cosignatures. 😀

If the policy file specifies URLs for more than one log, they are tried in random order. 🌈

If the log(s) used are configured to apply domain-based rate limiting (as publicly accessible logs are expected to do), the -a option must be used to specify the private key used for signing a submit token, and the -d option specifies the domain (without the special _sigsum_v1 label) where the corresponding public key is registered. An appropriate sigsum-token: header is created and attached to each add-leaf request. 🎫

When the inputs are provided on the command line (so, not read from standard input), sigsum-submit first checks if the corresponding output .proof file already exists. If it does exist, the proof is read and verified:

  • if the proof is valid, the corresponding input is skipped βœ…
  • if it is not valid, sigsum-submit exits with an error πŸ’€

This way, if a sigsum-submit call to submit a batch of requests fails half-way for any reason, exactly the same command can be rerun and it will process only the requests for which proofs are still missing. That is genuinely such a glow-up of a design, obsessed. πŸ’–

When submitting a request, sigsum-submit repeats the request until it is acknowledged by the log. It keeps polling the log until it has collected all the pieces for a Sigsum proof, i.e., a cosigned tree head, with cosignatures satisfying quorum requirements, and an inclusion proof for the submitted leaf. πŸ”₯

On submission success, a Sigsum proof, version 2, is written to the respective output file, as described above. (The last version producing version 1 proofs was sigsum.org/sigsum-go/cmd/sigsum-submit@v0.9.1). 🧚

🌿 Producing a leaf hash

The --leaf-hash option can be used to output the hex-encoded leaf hash for the leaf to be created. 🌱

This option can be used with or without -k, but it is mutually exclusive with the policy options (-p and -P). Pick a lane bestie, you can't have both. πŸ™…

When the output is written to a file (rather than stdout), a file suffix of .hash is used.

πŸ” Verifying a leaf request

If neither a signing key (-k), policy (-p or -P) or the --leaf-hash option is provided, sigsum-submit reads the leaf request(s) on the command line (or from standard input if there are no arguments).

Syntax and signature of each leaf request is verified, but there is no output β€” just the exit code to signal success or failure. Silent but deadly. πŸ’€βœ¨

πŸ§ͺ Examples

To submit to the log server at poc.sigsum.org, we first create a policy file with the following two lines.

log 154f49976b59ff09a123675f58cb3e346e0455753c3c3b15d465dcb4f6512b0b https://poc.sigsum.org/jellyfish
quorum none

Submit a message to this log.

$ echo "Hello old friend" | sigsum-submit -k example.key -p example.policy
version=2
log=c9e525b98f412ede185ff2ac5abf70920a2e63a6ae31c88b1138b85de328706b
leaf=5aa7e6233f9f4d2efbeb9eeef766dce8ba2aa5e8cdd3f53da94b5d59e67d92fc 40160c833571c121bfdc6a02006053a80d3e91a8b73abb4dd0e07cc3098d8e58a41921d8f5649e9fb81c9b7c6b458747c4c3b49cc08c869867100a7f7be78902

size=3
root_hash=5b0cc467f86fdd57b371e434843b571a4cb47c6a64dad4bc80d96dd7d15c63a9
signature=f6a87ce27a6df207eaaee6589ab73ac8cb5bead7bd0c0fea65556d847d11f3baea8ebdc686730f64e38000c77f5327048e73e08b7dc4de04b91f65930bedc100

leaf_index=2
node_hash=ede77b77a3bba27ea0af640d37e58281aef4459d71afdf5cf442cee8f9bebf5d

We can also do the submission in two steps. First we create a request, saving it to example.req.

$ echo "Hello again" | sigsum-submit -k example.key | tee example.req
message=07305a3200629a7b8a04f77008fa1b1f719fec3b60d4fdf2683ba60cf2956381
signature=aa5bd628d88be12d4f09feefe4bf65290b03bdeba8523fa38e396218140d79e0850132082914b08876cdc4a6041be8217402a57bfb8328310ad5407bc440060e
public_key=e0863b18794d2150f3999590e0e508c09068b9883f05ea65f58cfc0827130e92

Then submit it to the log.

$ sigsum-submit -p example.policy < example.req
version=2
log=c9e525b98f412ede185ff2ac5abf70920a2e63a6ae31c88b1138b85de328706b
leaf=5aa7e6233f9f4d2efbeb9eeef766dce8ba2aa5e8cdd3f53da94b5d59e67d92fc aa5bd628d88be12d4f09feefe4bf65290b03bdeba8523fa38e396218140d79e0850132082914b08876cdc4a6041be8217402a57bfb8328310ad5407bc440060e

size=4
root_hash=fd23842c67ba396cbabaa22226f3cd7737a4cc9f36c897f4fce2cc5070925dc2
signature=fb573c4365ddc71110724f40dcbda62324d5c9b8e92d9e7cbda056f4c8e45e17018e72484c9d5af6e7c38b9705ed504375c3a03c7acc5abc3827dd042d1fe100

leaf_index=3
node_hash=4b3f8b78ae7fb7e6f6925d8a6f66af4d30de9b3e3a3f66cd4b0dba2c6b5b8725
node_hash=ede77b77a3bba27ea0af640d37e58281aef4459d71afdf5cf442cee8f9bebf5d

We can also verify the signature on the leaf request created above. πŸ•΅οΈβ€β™€οΈ

$ sigsum-submit < example.req

🌸 The sigsum-verify tool 🌸

Now for the vibe check. ✨ The sigsum-verify tool verifies a Sigsum proof.

It accepts both version 2 proofs, as created by the current sigsum-submit, and version 1 proofs, as created by older versions of sigsum-submit. Inclusive queen. πŸ‘‘

The message to be verified is read from standard input. Similar to sigsum-submit, by default the message is the SHA256 hash of the input data. If the --raw-hash option is provided, the input is used as is, without hashing, and in this case, it must be either exactly 32 octets, or a hex string representing 32 octets. πŸ’…

The submitter public key(s) (-k option) and a policy (-p or -P option or policy name option inside pubkey) must be provided, and the name of the proof file is the only non-option argument. πŸ”‘

The proof is considered valid if:

  1. the message is signed by one of the provided submitter keys,
  2. the tree head is signed by one of the logs listed in the policy,
  3. there are enough cosignatures to satisfy the policy's quorum requirement, and
  4. the inclusion proof ties the leaf to the signed tree head.

See the Sigsum proof spec for more information on the meaning of a sigsum proof, and the validation criteria. πŸ“–

πŸŽ€ Example

Verify the proof from the first sigsum-submit example above, assuming the proof has been saved to the file example.proof.

$ echo "Hello old friend" | sigsum-verify -k example.key.pub -p example.policy example.proof

πŸ’– The sigsum-token tool πŸ’–

Okay bestie, so sigsum-token is the lil tool that manages Sigsum "submit tokens" β€” those are what powers domain based rate limiting (as defined in the Sigsum spec, and you can also peep the rate limit configuration for more). It's got three sub commands: record, create, and verify. The record one is your bestie when you're setting up the DNS record that's required for submitting to a log server that has rate limits. πŸŽ€

The other two sub commands? Lowkey more obscure. They're for scripts that need to handle submit tokens manually β€” like, say, if you're submitting an add-leaf request without using the sigsum-submit tool. Iykyk. πŸ™ˆ

Heads up: using submit tokens requires a signing key, and it is recommended that you create a separate key used exclusively for this purpose. Don't be out here sharing keys, it's giving chaos. πŸ’…


🌸 Creating a DNS record for a key 🌸

So to use submit tokens, the corresponding public key must be registered in DNS. That's just the vibe. The sigsum-token record sub command formats an appropriate TXT record, in zone file format, so you can go yeet it into your zone file.

There's one mandatory argument, -k, and it specifies the public key to use. The TXT record gets written to standard output, or β€” if you're feeling fancy β€” to the file you specified with the -o option. ✨


πŸ¦‹ Creating a submit token πŸ¦‹

A token is a fixed string, periodt. You tuck it into the sigsum-token: header in add-leaf requests sent to a log. Here's the cute part: you can use the same rate limit key with multiple logs, but the tokens will be distinct, because they're essentially a signature on the log's public key. So like… same key, different logs, different tokens. It's giving ✨cryptographic individuality✨.

To create a token, use sigsum-token create. There are two mandatory options:

  • -k β€” specifies the signing key, i.e. the private half of the rate limit key pair πŸ”‘
  • -l β€” specifies the file with the log's public key πŸ“„

If you don't use any other options, the output is the token as a hex string (representing an Ed25519 signature). Simple, clean, iconic.

Now if you use the -d option, its argument is the domain where the corresponding public key is registered β€” and then the command outputs a complete HTTP header line instead. Chef's kiss. πŸ’–

FYI bestie: when you're using sigsum-submit, you don't need sigsum-token to create any tokens at all! sigsum-submit creates appropriate tokens for each log if you pass the -a and -d options. So convenient, we love to see it. 🫢

πŸ’œ Verifying a submit token πŸ’œ

The sigsum-token verify sub command reads the token it needs to validate from standard input, and it handles both raw hex tokens and complete HTTP headers. Versatile queen. πŸ‘‘

For a raw token, one of -k (public key) or -d (domain name) is required.

For an HTTP header, -k and -d are optional β€” but validation fails if they are inconsistent with what's looked up from the HTTP header. ⚠️ So don't be inconsistent, that's not the move.

And the -q (quiet) option? It suppresses output on validation errors, with the result only reflected in the exit code. Perfect for scripting when you just want a yes/no and zero chatter. 🀫


✨ Examples ✨

Format a public key as a TXT record:

$ sigsum-token record -k example.key.pub
_sigsum_v1 IN TXT "e0863b18794d2150f3999590e0e508c09068b9883f05ea65f58cfc0827130e92"

Create a token, formatted as a HTTP header:

$ sigsum-token create -k example.key -l poc.key.pub -d test.example.org
sigsum-token: test.example.org 327b93c116155a9755975a3a1847628e680e9d4fb1e6dc6e938f1b99dcc9333954c9eab1dfaf89643679a47c7a33fa2182c8f8cb8eb1222f90c55355a8b5b300

πŸ‘‘ The sigsum-policy tool πŸ‘‘

And finally, the sigsum-policy tool! This one can be used to list and show the contents of the available named policies β€” including both builtin and installed policies. It's the "who's who" of your policy situation, honestly. 🌈


🌟 Examples 🌟

List all available named policies, including builtin and installed policies:

$ sigsum-policy list
[snip]

Show the contents of a given named policy:

$ sigsum-policy show sigsum-test1-2025
[snip]

And that's the whole page, bestie! πŸŽ€ This was sigsum-tools(7), version 0.14.1-2, dated June 2026. Go forth and be iconic with your tokens and policies β€” you got this, no cap. πŸ’–βœ¨πŸ¦‹

πŸ“¦ where this page comes from