summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNora Widdecke <nora@sequoia-pgp.org>2022-07-19 11:41:40 +0200
committerNora Widdecke <nora@sequoia-pgp.org>2022-07-20 10:22:25 +0200
commit7d76a57c6b372b0549aa7f8750c32cb812ec2fcc (patch)
treeaa942b4a27d7aa2346a2dc142f0ff3f2eb31a424
parentfd8912e4bf9baf02ea2cf4adddfb6d7258aeadf0 (diff)
sq: Clean up build.
- Remove the workaround that was required to include help output in docs.
-rw-r--r--.gitlab-ci.yml4
-rw-r--r--sq/Cargo.toml2
-rw-r--r--sq/build.rs34
-rw-r--r--sq/sq-usage.md2177
-rw-r--r--sq/src/sq-usage.rs2182
-rw-r--r--sq/src/sq.rs5
6 files changed, 2198 insertions, 2206 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ccd35486..77154b5e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -55,7 +55,7 @@ bookworm:
- cargo run --manifest-path openpgp/Cargo.toml --no-default-features --features crypto-nettle,compression --example supported-algorithms
- $MAKE_TOP test
- if ! git diff --quiet Cargo.lock ; then echo "Cargo.lock changed. Please add the change to the corresponding commit." ; git diff ; false ; fi
- - if ! git diff --quiet sq ; then echo "Please commit the changes to sq/src/sq-usage.rs." ; false ; fi
+ - if ! git diff --quiet sq ; then echo "Please commit the changes to sq/sq-usage.md." ; false ; fi
- if ! git diff --quiet ; then echo "The build changed the source. Please investigate." ; git diff ; fi
variables:
CARGO_TARGET_DIR: /target
@@ -74,7 +74,7 @@ bookworm:arm64:
script:
- $MAKE_TOP test
- if ! git diff --quiet Cargo.lock ; then echo "Cargo.lock changed. Please add the change to the corresponding commit." ; false ; fi
- - if ! git diff --quiet sq ; then echo "Please commit the changes to sq/src/sq-usage.rs." ; false ; fi
+ - if ! git diff --quiet sq ; then echo "Please commit the changes to sq/src/sq-usage.md." ; false ; fi
- if ! git diff --quiet ; then echo "The build changed the source. Please investigate." ; git diff ; fi
variables:
CARGO_TARGET_DIR: /target
diff --git a/sq/Cargo.toml b/sq/Cargo.toml
index 6ec451c6..dec36b47 100644
--- a/sq/Cargo.toml
+++ b/sq/Cargo.toml
@@ -59,7 +59,7 @@ predicates = "2"
[[bin]]
name = "sq"
-path = "src/sq-usage.rs"
+path = "src/sq.rs"
bench = false
[features]
diff --git a/sq/build.rs b/sq/build.rs
index 2264c000..218144d7 100644
--- a/sq/build.rs
+++ b/sq/build.rs
@@ -11,23 +11,17 @@ pub mod sq_cli {
fn main() {
println!("cargo:rerun-if-changed=build.rs");
- // XXX: Revisit once
- // https://github.com/rust-lang/rust/issues/44732 is stabilized.
-
+ // Generate subplot tests.
subplot_build::codegen(Path::new("sq-subplot.md"))
.expect("failed to generate code with Subplot");
+ // Dump help output of all commands and subcommands, for inlcusion in docs
let mut sq = sq_cli::build().term_width(80);
- let mut main = fs::File::create("src/sq-usage.rs").unwrap();
+ let mut main = fs::File::create("sq-usage.md").unwrap();
dump_help(&mut main,
&mut sq,
vec![],
"#").unwrap();
- writeln!(main, "\n#![doc(html_favicon_url = \"https://docs.sequoia-pgp.org/favicon.png\")]")
- .unwrap();
- writeln!(main, "#![doc(html_logo_url = \"https://docs.sequoia-pgp.org/logo.svg\")]")
- .unwrap();
- writeln!(main, "\ninclude!(\"sq.rs\");").unwrap();
let outdir = match env::var_os("CARGO_TARGET_DIR") {
None => return,
@@ -43,7 +37,7 @@ fn main() {
};
}
-fn dump_help(sink: &mut dyn io::Write,
+fn dump_help(sink: &mut dyn Write,
sq: &mut clap::Command,
cmd: Vec<String>,
heading: &str)
@@ -51,15 +45,15 @@ fn dump_help(sink: &mut dyn io::Write,
{
if cmd.is_empty() {
- writeln!(sink, "//! A command-line frontend for Sequoia.")?;
- writeln!(sink, "//!")?;
- writeln!(sink, "//! # Usage")?;
+ writeln!(sink, "A command-line frontend for Sequoia.")?;
+ writeln!(sink, "")?;
+ writeln!(sink, "# Usage")?;
} else {
- writeln!(sink, "//!")?;
- writeln!(sink, "//! {} Subcommand {}", heading, cmd.join(" "))?;
+ writeln!(sink, "")?;
+ writeln!(sink, "{} Subcommand {}", heading, cmd.join(" "))?;
}
- writeln!(sink, "//!")?;
+ writeln!(sink, "")?;
let args = std::iter::once("sq")
.chain(cmd.iter().map(|s| s.as_str()))
@@ -69,15 +63,15 @@ fn dump_help(sink: &mut dyn io::Write,
let help = sq.try_get_matches_from_mut(&args)
.unwrap_err().to_string();
- writeln!(sink, "//! ```text")?;
+ writeln!(sink, "```text")?;
for line in help.trim_end().split('\n').skip(1) {
if line.is_empty() {
- writeln!(sink, "//!")?;
+ writeln!(sink, "")?;
} else {
- writeln!(sink, "//! {}", line.trim_end())?;
+ writeln!(sink, "{}", line.trim_end())?;
}
}
- writeln!(sink, "//! ```")?;
+ writeln!(sink, "```")?;
// Recurse.
let mut found_subcommands = false;
diff --git a/sq/sq-usage.md b/sq/sq-usage.md
new file mode 100644
index 00000000..5f0cf511
--- /dev/null
+++ b/sq/sq-usage.md
@@ -0,0 +1,2177 @@
+A command-line frontend for Sequoia.
+
+# Usage
+
+```text
+A command-line frontend for Sequoia, an implementation of OpenPGP
+
+Functionality is grouped and available using subcommands. Currently,
+this interface is completely stateless. Therefore, you need to supply
+all configuration and certificates explicitly on each invocation.
+
+OpenPGP data can be provided in binary or ASCII armored form. This
+will be handled automatically. Emitted OpenPGP data is ASCII armored
+by default.
+
+We use the term "certificate", or cert for short, to refer to OpenPGP
+keys that do not contain secrets. Conversely, we use the term "key"
+to refer to OpenPGP keys that do contain secrets.
+
+USAGE:
+ sq [OPTIONS] <SUBCOMMAND>
+
+OPTIONS:
+ -f, --force
+ Overwrites existing files
+
+ -h, --help
+ Print help information
+
+ --known-notation <NOTATION>
+ Adds NOTATION to the list of known notations. This is used when
+ validating signatures. Signatures that have unknown notations with
+ the critical bit set are considered invalid.
+
+ --output-format <FORMAT>
+ Produces output in FORMAT, if possible
+
+ [env: SQ_OUTPUT_FORMAT=]
+ [default: human-readable]
+ [possible values: human-readable, json]
+
+ --output-version <VERSION>
+ Produces output variant VERSION
+
+ [env: SQ_OUTPUT_VERSION=]
+
+ -V, --version
+ Print version information
+
+SUBCOMMANDS:
+ encrypt
+ Encrypts a message
+ decrypt
+ Decrypts a message
+ sign
+ Signs messages or data files
+ verify
+ Verifies signed messages or detached signatures
+ key
+ Manages keys
+ keyring
+ Manages collections of keys or certs
+ certify
+ Certifies a User ID for a Certificate
+ autocrypt
+ Communicates certificates using Autocrypt
+ keyserver
+ Interacts with keyservers
+ wkd
+ Interacts with Web Key Directories
+ armor
+ Converts binary to ASCII
+ dearmor
+ Converts ASCII to binary
+ inspect
+ Inspects data, like file(1)
+ packet
+ Low-level packet manipulation
+ revoke
+ Generates revocation certificates
+ help
+ Print this message or the help of the given subcommand(s)
+```
+
+## Subcommand encrypt
+
+```text
+Encrypts a message
+
+Encrypts a message for any number of recipients and with any number of
+passwords, optionally signing the message in the process.
+
+The converse operation is "sq decrypt".
+
+USAGE:
+ sq encrypt [OPTIONS] [FILE]
+
+ARGS:
+ <FILE>
+ Reads from FILE or stdin if omitted
+
+OPTIONS:
+ -B, --binary
+ Emits binary data
+
+ --compression <KIND>
+ Selects compression scheme to use
+
+ [default: pad]
+ [possible values: none, pad, zip, zlib, bzip2]
+
+ -h, --help
+ Print help information
+
+ --mode <MODE>
+ Selects what kind of keys are considered for encryption. Transport
+ select subkeys marked as suitable for transport encryption, rest
+ selects those for encrypting data at rest, and all selects all
+ encryption-capable subkeys.
+
+ [default: all]
+ [possible values: transport, rest, all]
+
+ -o, --output <FILE>
+ Writes to FILE or stdout if omitted
+
+ --private-key-store <KEY_STORE>
+ Provides parameters for private key store
+
+ --recipient-cert <CERT-RING>
+ Encrypts for all recipients in CERT-RING
+
+ -s, --symmetric
+ Adds a password to encrypt with. The message can be decrypted with
+ either one of the recipient's keys, or any password.
+
+ --signer-key <KEY>
+ Signs the message with KEY
+
+ -t, --time <TIME>
+ Chooses keys valid at the specified time and sets the signature's
+ creation time
+
+ --use-expired-subkey
+ If a certificate has only expired encryption-capable subkeys, falls
+ back to using the one that expired last
+
+EXAMPLES:
+
+# Encrypt a file using a certificate
+$ sq encrypt --recipient-cert romeo.pgp message.txt
+
+# Encrypt a file creating a signature in the process
+$ sq encrypt --recipient-cert romeo.pgp --signer-key juliet.pgp message.txt
+
+# Encrypt a file using a password
+$ sq encrypt --symmetric message.txt
+```
+
+## Subcommand decrypt
+
+```text
+Decrypts a message
+
+Decrypts a message using either supplied keys, or by prompting for a
+password. If message tampering is detected, an error is returned.
+See below for details.
+
+If certificates are supplied using the "--signer-cert" option, any
+signatures that are found are checked using these certificates.
+Verification is only successful if there is no bad signature, and the
+number of successfully verified signatures reaches the threshold
+configured with the "--signatures" parameter.
+
+If the signature verification fails, or if message tampering is
+detected, the program terminates with an exit status indicating
+failure. In addition to that, the last 25 MiB of the message are
+withheld, i.e. if the message is smaller than 25 MiB, no output is
+produced, and if it is larger, then the output will be truncated.
+
+The converse operation is "sq encrypt".
+
+USAGE:
+ sq decrypt [OPTIONS] [FILE]
+
+ARGS:
+ <FILE>
+ Reads from FILE or stdin if omitted
+
+OPTIONS:
+ --dump
+ Prints a packet dump to stderr
+
+ --dump-session-key
+ Prints the session key to stderr
+
+ -h, --help
+ Print help information
+
+ -n, --signatures <N>
+ Sets the threshold of valid signatures to N. The message will only
+ be considered verified if this threshold is reached. [default: 1 if
+ at least one signer cert file is given, 0 otherwise]
+
+ -o, --output <FILE>
+ Writes to FILE or stdout if omitted
+
+ --private-key-store <KEY_STORE>
+ Provides parameters for private key store
+
+ --recipient-key <KEY>
+ Decrypts with KEY
+
+ --session-key <SESSION-KEY>
+ Decrypts an encrypted message using SESSION-KEY
+
+ --signer-cert <CERT>
+ Verifies signatures with CERT
+
+ -x, --hex
+ Prints a hexdump (implies --dump)
+
+EXAMPLES:
+
+# Decrypt a file using a secret key
+$ sq decrypt --recipient-key juliet.pgp ciphertext.pgp
+
+# Decrypt a file verifying signatures
+$ sq decrypt --recipient-key juliet.pgp --signer-cert romeo.pgp ciphertext.pgp
+
+# Decrypt a file using a password
+$ sq decrypt ciphertext.pgp
+```
+
+## Subcommand sign
+
+```text
+Signs messages or data files
+
+Creates signed messages or detached signatures. Detached signatures
+are often used to sign software packages.
+
+The converse operation is "sq verify".
+
+USAGE:
+ sq sign [OPTIONS] [--] [FILE]
+
+ARGS:
+ <FILE>
+ Reads from FILE or stdin if omitted
+
+OPTIONS:
+ -a, --append
+ Appends a signature to existing signature
+
+ -B, --binary
+ Emits binary data
+
+ --cleartext-signature
+ Creates a cleartext signature
+
+ --detached
+ Creates a detached signature
+
+ -h, --help
+ Print help information
+
+ --merge <SIGNED-MESSAGE>
+ Merges signatures from the input and SIGNED-MESSAGE
+
+ -n, --notarize
+ Signs a message and all existing signatures
+
+ --notation <NAME> <VALUE>
+ Adds a notation to the certification. A user-defined notation's
+ name must be of the form "name@a.domain.you.control.org". If the
+ notation's name starts with a !, then the notation is marked as
+ being critical. If a consumer of a signature doesn't understand a
+ critical notation, then it will ignore the signature. The notation
+ is marked as being human readable.
+
+ -o, --output <FILE>
+ Writes to FILE or stdout if omitted
+
+ --private-key-store <KEY_STORE>
+ Provides parameters for private key store
+
+ --signer-key <KEY>
+ Signs using KEY
+
+ -t, --time <TIME>
+ Chooses keys valid at the specified time and sets the signature's
+ creation time
+
+EXAMPLES:
+
+# Create a signed message
+$ sq sign --signer-key juliet.pgp message.txt
+
+# Create a detached signature
+$ sq sign --detached --signer-key juliet.pgp message.txt
+```
+
+## Subcommand verify
+
+```text
+Verifies signed messages or detached signatures
+
+When verifying signed messages, the message is written to stdout or
+the file given to --output.
+
+When a detached message is verified, no output is produced. Detached
+signatures are often used to sign software packages.
+
+Verification is only successful if there is no bad signature, and the
+number of successfully verified signatures reaches the threshold
+configured with the "--signatures" parameter. If the verification
+fails, the program terminates with an exit status indicating failure.
+In addition to that, the last 25 MiB of the message are withheld,
+i.e. if the message is smaller than 25 MiB, no output is produced, and
+if it is larger, then the output will be truncated.
+
+The converse operation is "sq sign".
+
+USAGE:
+ sq verify [OPTIONS] [FILE]
+
+ARGS:
+ <FILE>
+ Reads from FILE or stdin if omitted
+
+OPTIONS:
+ --detached <SIG>
+ Verifies a detached signature
+
+ -h, --help
+ Print help information
+
+ -n, --signatures <N>
+ Sets the threshold of valid signatures to N. If this threshold is
+ not reached, the message will not be considered verified.
+
+ [default: 1]
+
+ -o, --output <FILE>
+ Writes to FILE or stdout if omitted
+
+ --signer-cert <CERT>
+ Verifies signatures with CERT
+
+EXAMPLES:
+
+# Verify a signed message
+$ sq verify --signer-cert juliet.pgp signed-message.pgp
+
+# Verify a detached message
+$ sq verify --signer-cert juliet.pgp --detached message.sig message.txt
+
+SEE ALSO:
+
+If you are looking for a standalone program to verify detached
+signatures, consider using sequoia-sqv.
+```
+
+## Subcommand key
+
+```text
+Manages keys
+
+We use the term "key" to refer to OpenPGP keys that do contain
+secrets. This subcommand provides primitives to generate and
+otherwise manipulate keys.
+
+Conversely, we use the term "certificate", or cert for short, to refer
+to OpenPGP keys that do not contain secrets. See "sq keyring" for
+operations on certificates.
+
+USAGE:
+ sq key <SUBCOMMAND>
+
+OPTIONS:
+ -h, --help
+ Print help information
+
+SUBCOMMANDS:
+ generate
+ Generates a new key
+ password
+ Changes password protecting secrets
+ userid
+ Manages User IDs
+ extract-cert
+ Converts a key to a cert
+ attest-certifications
+ Attests to third-party certifications
+ adopt
+ Binds keys from one certificate to another
+ help
+ Print this message or the help of the given subcommand(s)
+```
+
+### Subcommand key generate
+
+```text
+Generates a new key
+
+Generating a key is the prerequisite to receiving encrypted messages
+and creating signatures. There are a few parameters to this process,
+but we provide reasonable defaults for most users.
+
+When generating a key, we also generate a revocation certificate.
+This can be used in case the key is superseded, lost, or compromised.
+It is a good idea to keep a copy of this in a safe place.
+
+After generating a key, use "sq key extract-cert" to get the
+certificate corresponding to the key. The key must be kept secure,
+while the certificate should be handed out to correspondents, e.g. by
+uploading it to a keyserver.
+
+USAGE:
+ sq key generate [OPTIONS]
+
+OPTIONS:
+ -c, --cipher-suite <CIPHER-SUITE>
+ Selects the cryptographic algorithms for the key
+
+ [default: cv25519]
+ [possible values: rsa3k, rsa4k, cv25519]
+
+ --can-authenticate
+ Adds an authentication-capable subkey (default)
+
+ --can-encrypt <PURPOSE>
+ Adds an encryption-capable subkey. Encryption-capable subkeys can be
+ marked as suitable for transport encryption, storage encryption, or
+ both. [default: universal]
+
+ [possible values: transport, storage, universal]
+
+ --can-sign
+ Adds a signing-capable subkey (default)
+
+ --cannot-authenticate
+ Adds no authentication-capable subkey
+
+ --cannot-encrypt
+ Adds no encryption-capable subkey
+
+ --cannot-sign
+ Adds no signing-capable subkey
+
+ --creation-time <CREATION_TIME>
+ Sets the key's creation time to TIME. TIME is interpreted as an ISO
+ 8601
+ timestamp. To set the creation time to June 9, 2011 at midnight
+ UTC,
+ you can do:
+
+ $ sq key generate --creation-time 20110609 --export noam.pgp
+
+ To include a time, add a T, the time and optionally the timezone
+ (the
+ default timezone is UTC):
+
+ $ sq key generate --creation-time 20110609T1938+0200 --export
+ noam.pgp
+
+ -e, --export <OUTFILE>
+ Writes the key to OUTFILE
+
+ --expires <TIME>
+ Makes the key expire at TIME (as ISO 8601). Use "never" to create
+ keys that do not expire.
+
+ --expires-in <DURATION>
+ Makes the key expire after DURATION. Either "N[ymwds]", for N years,
+ months, weeks, days, seconds, or "never".
+
+ -h, --help
+ Print help information
+
+ --rev-cert <FILE or ->
+ Writes the revocation certificate to FILE. mandatory if OUTFILE is
+ "-". [default: <OUTFILE>.rev]
+
+ -u, --userid <EMAIL>
+ Adds a userid to the key
+
+ --with-password
+ Protects the key with a password
+
+EXAMPLES:
+
+# First, this generates a key
+$ sq key generate --userid "<juliet@example.org>" --export juliet.key.pgp
+
+# Then, this extracts the certificate for distribution
+$ sq key extract-cert --output juliet.cert.pgp juliet.key.pgp
+
+# Generates a key protecting it with a password
+$ sq key generate --userid "<juliet@example.org>" --with-password
+
+# Generates a key with multiple userids
+$ sq key generate --userid "<juliet@example.org>" --userid "Juliet Capulet"
+```
+
+### Subcommand key password
+
+```text
+Changes password protecting secrets
+
+Secret key material in keys can be protected by a password. This
+subcommand changes or clears this encryption password.
+
+To emit the key with unencrypted secrets, either use `--clear` or
+supply a zero-length password when prompted for the new password.
+
+USAGE:
+ sq key password [OPTIONS] [FILE]
+
+ARGS:
+ <FILE>
+ Reads from FILE or stdin if omitted
+
+OPTIONS:
+ -B, --binary
+ Emits binary data
+
+ --clear
+ Emit a key with unencrypted secrets
+
+ -h, --help
+ Print help information
+
+ -o, --output <FILE>
+ Writes to FILE or stdout if omitted
+
+EXAMPLES:
+
+# First, generate a key
+$ sq key generate --userid "<juliet@example.org>" --export juliet.key.pgp
+
+# Then, encrypt the secrets in the key with a password.
+$ sq key password < juliet.key.pgp > juliet.encrypted_key.pgp
+
+# And remove the password again.
+$ sq key password --clear < juliet.encrypted_key.pgp > juliet.decrypted_key.pgp
+```
+
+### Subcommand key userid
+
+```text
+Manages User IDs
+
+Add User IDs to, or strip User IDs from a key.
+
+USAGE:
+ sq key userid <SUBCOMMAND>
+
+OPTIONS:
+ -h, --help
+ Print help information
+
+SUBCOMMANDS:
+ add
+ Adds a User ID
+ strip
+ Strips a User ID
+ help
+ Print this message or the help of the given subcommand(s)
+```
+
+#### Subcommand key userid add
+
+```text
+Adds a User ID
+
+A User ID can contain a name, like "Juliet" or an email address, like
+"<juliet@example.org>". Historically, a name and email address were often
+combined as a single User ID, like "Juliet <juliet@example.org>".
+
+USAGE:
+ sq key userid add [OPTIONS] [FILE]
+
+ARGS:
+ <FILE>
+ Reads from FILE or stdin if omitted
+
+OPTIONS:
+ -B, --binary
+ Emits binary data
+
+ --creation-time <CREATION_TIME>
+ Sets the creation time of this User ID's binding signature to TIME.
+ TIME is interpreted as an ISO 8601 timestamp. To set the creation
+ time to June 28, 2022 at midnight UTC, you can do:
+
+ $ sq key userid add --userid "Juliet" --creation-time 20210628 \
+ juliet.key.pgp --output juliet-new.key.pgp
+
+ To include a time, add a T, the time and optionally the timezone
+ (the
+ default timezone is UTC):
+
+ $ sq key userid add --userid "Juliet" --creation-time
+ 20210628T1137+0200 \
+ juliet.key.pgp --output juliet-new.key.pgp
+
+ -h, --help
+ Print help information
+
+ -o, --output <FILE>
+ Writes to FILE or stdout if omitted
+
+ --private-key-store <KEY_STORE>
+ Provides parameters for private key store
+
+ -u, --userid <USERID>
+ User ID to add
+
+EXAMPLES:
+
+# First, this generates a key
+$ sq key generate --userid "<juliet@example.org>" --export juliet.key.pgp
+
+# Then, this adds a User ID
+$ sq key userid add --userid "Juliet" juliet.key.pgp \
+ --output juliet-new.key.pgp
+```
+
+#### Subcommand key userid strip
+
+```text
+Strips a User ID
+
+Note that this operation does not reliably remove User IDs from a
+certificate that has already been disseminated! (OpenPGP software
+typically appends new information it receives about a certificate
+to its local copy of that certificate. Systems that have obtained
+a copy of your certificate with the User ID that you are trying to
+strip will not drop that User ID from their copy.)
+
+In most cases, you will want to use the 'sq revoke userid' operation
+instead. That issues a revocation for a User ID, which can be used to mark
+the User ID as invalidated.
+
+However, this operation can be useful in very specific cases, in particular:
+to remove a mistakenly added User ID before it has been uploaded to key
+servers or otherwise shared.
+
+Stripping a User ID may change how a certificate is interpreted. This
+is because information about the certificate like algorithm preferences,
+the primary key's key flags, etc. is stored in the User ID's binding
+signature.
+
+USAGE:
+ sq key userid strip [OPTIONS] [FILE]
+
+ARGS:
+ <FILE>
+ Reads from FILE or stdin if omitted
+
+OPTIONS:
+ -B, --binary
+ Emits binary data
+
+ -h, --help
+ Print help information
+
+ -o, --output <FILE>
+ Writes to FILE or stdout if omitted
+
+ -u, --userid <USERID>
+ The User IDs to strip. Values must exactly match a User ID.
+
+EXAMPLES:
+
+# First, this generates a key
+$ sq key generate --userid "<juliet@example.org>" --export juliet.key.pgp
+
+# Then, this strips a User ID
+$ sq key userid strip --userid "<juliet@example.org>" \
+ --output juliet-new.key.pgp juliet.key.pgp
+```
+
+### Subcommand key extract-cert
+
+```text
+Converts a key to a cert
+
+After generating a key, use this command to get the certificate
+corresponding to the key. The key must be kept secure, while the
+certificate should be handed out to correspondents, e.g. by uploading
+it to a keyserver.
+
+USAGE:
+ sq key extract-cert [OPTIONS] [FILE]
+
+ARGS:
+ <FILE>
+ Reads from FILE or stdin if omitted
+
+OPTIONS:
+ -B, --binary
+ Emits binary data
+
+ -h, --help
+ Print help information
+
+ -o, --output <FILE>
+ Writes to FILE or stdout if omitted
+
+EXAMPLES:
+
+# First, this generates a key
+$ sq key generate --userid "<juliet@example.org>" --export juliet.key.pgp
+
+# Then, this extracts the certificate for distribution
+$ sq key extract-cert --output juliet.cert.pgp juliet.key.pgp
+```
+
+### Subcommand key attest-certifications
+
+```text
+
+Attests to third-party certifications allowing for their distribution
+
+To prevent certificate flooding attacks, modern key servers prevent
+uncontrolled distribution of third-party certifications on
+certificates. To make the key holder the sovereign over the
+information over what information is distributed with the certificate,
+the key holder needs to explicitly attest to third-party
+certifications.
+
+After the attestation has been created, the certificate has to be
+distributed, e.g. by uploading it to a keyserver.
+
+USAGE:
+ sq key attest-certifications [OPTIONS] [KEY]