About this guide

This guide is about sq, the command line interface to Sequoia PGP.

This guide is work in progress

sq currently evolves fast and it's challenging to keep up. In doubt, consult the help- and/or man-pages.


Intended Content

  • Introduction
  • Overview, where to find what

Conventions, type setting and license

Suffixes

This guide uses the following filename suffixes:

  • certs: .cert, e.g.: juliet.cert
  • keys: .key
  • messages: .pgp
  • csf messages: .txt
  • detached signatures: .sig
  • data files: .data
  • revocation certificates: .rev

Type settings

We present “typescripts” of command line use like this:

$ sq version
sq 0.38.0
using sequoia-openpgp 1.21.2
with cryptographic backend Nettle 3.8 (Cv448: true, OCB: false)

The first line is the shell command. The $ represents the shell prompt: the dollar sign is traditional for Unix, but it’s likely that your actual prompt is different. The rest of the line is the command you write to invoke a command. The rest of the typescript is the output of the command. A typescript may contain multiple commands, and are all identified by a leading dollar sign.

This guide is licensed under the Creative Commons Attribution-ShareAlike (CC-BY-SA) 4.0 International license. It is based on https://creativecommons.org/licenses/by-sa/4.0/legalcode.txt, but typeset via Markdown, using commit b1a347d40d2a50ed345a9b152248cca6b9f0f803 of Creative-Commons-Markdown.git. It matches the plain text version, linked above, except for typesetting. In case of differences, the plain text version is authoritative.

About sq and Sequoia PGP

Sequoia PGP is an implementation of the OpenPGP standard written in Rust. It's comes in the form of a library that other applications can integrate to use OpenPGP functionality without reinventing the wheel. sq is a command line application using Sequoia PGP in such a way.

sq aims to expose a useful set of OpenPGP functionality for common tasks: encryption/decryption signing/verifying, key and certificate management, certification and the like.

OpenPGP is a complex and elaborated standard, addressing issues of privacy and authenticity. As such it's not easy to digest, sq delivers an opinionated approach, making OpenPGP accessible and (hopefully) easy to use without sacrificing the goals of OpenPGP.

sq aims to safe by default, that doesn't mean that you cannot do stupid or dangerous things with sq, but the easy, default way of using sq is the safe way.

Design and specialties

sq (and Sequoia PGP for that matter) uses a specific terminology when addressing keys (public and private) - please make sure to read the chapter on terminology for an overview.

There is no "automatic trust". Having a (secret) key in your key store doesn't imply that you "trust" signatures and certifications issued by that key. There is an extra step necessary, which protects against unwanted consequences of inadvertently imported keys. The same holds true for certificates ('public keys'), sq wants you to be certain when designating a certificate.

sq doesn't use keyrings (by default), there are stores. While the key store operates similar to a keyring, the certificate store is more like a cache. Trust relationships are managed within the PKI, which is a separate entity.

sq tries to minimize user interaction (for instance, in the form of yes/no questions). The design of the user interface aims to make these kind of questions superfluous.

sq uses subcommands to structure its interface. It has help-pages for each subcommand in the hierarchy to help with orientation. Alternatively TAB-expansion gives you a first glimpse (and avoids typing long option names or subcommands).

sq is stateful. It operates on its stores and updates them according to the used operations. While there are ways to avoid these updates and work in a stateless fashion, it's not the default mode of operation. If you are looking for statelessness, have a look at sqop (TODO: add link).

Getting started

Let's start with a short overview of some terminology, the toplevel structure of sq and some features to support you using sq.

Terminology

Keys and certificates

sq uses a different terminology when it comes to certain cryptographic artifacts. What is known as "public key" in other OpenPGP software (like gpg) is called a "certificate" in sq. "Private keys" are just called "keys". For the rational of this renaming see chapter Background: Keys and certificates.

Stores instead of keyrings

Some popular OpenPGP softwares store their artifacts in keyrings (secring.pgp, pubring.pgp), sq uses stores for that. Keys are stored in the key store, certificates in the cert store. sq has (limited) support for keyrings to help (for instance) with migration.

"Authenticated"

"Authenticated" in the context of sq means: "The right thing". Its main usage is in the selection or designation of a certificate. If you designate a certificate by its fingerprint, this designation is distinct, as fingerprints are unique. Designating by User ID is not, as these cannot be deduced from the key material like a fingerprint. To use the binding between a certificate and a User ID to designate a certificate (for instance to select a certificate by an email address), this binding has to be authenticated. It has to be manually marked as valid.

Public Key Infrastructure (PKI)

sq does not support implicit authentication: It's not enough to just import a certificate (aka public key) to use it. You have to authenticate the User IDs in it beforehand - declaring a "trust relationship".

These relationships are managed within the PKI. You can think of it as your local Web of Trust.

Structure of the interface

The functionality of sq is split into categories. Related functionality is located in the same category, sometimes even in subcategories.

The top level as orientation:

  • encrypt Encryption of messages or data files
  • decrypt Decryption of messages or data files
  • sign Signing messages or data files
  • verify Verify signed messages or detached signatures
  • download Download and authenticate a file in one go
  • inspect Inspect data, like file(1). Works on files, but also on objects in the different stores like certificates or keys.
  • cert Manage certificates. Import, export, list and the like.
  • key Manage keys. Generating, revoking, listing, import/export, updating metadata like expiry date and more.
  • pki This is where your "trust management" lives. Authenticating, lookup, trust paths and amounts and more.
  • network Retrieve and publish certificates over the network.
  • keyring Manage collections of keys or certs in files
  • packet Low-level packet manipulation
  • config Get configuration options
  • version Detailed version and output version information
  • help Print this message or the help of the given subcommand(s)

For example, you can list your keys with:

$ sq key list
Help

sq has help pages for every command. If in doubt, use:

$ sq some commmand --help

to get a short overview of parameters and functionality of said command. You can also use:

$ sq help some command
TAB-completion

sq comes with TAB-completion:

$ sq command <TAB><TAB>

shows you possible continuations of the command: available subcommands, parameters and other options. Likewise sq com<TAB><TAB> will expand to sq command .

Hints

After completing a command, sq prints some hints for possible follow up commands:

$ sq key generate --own-key --email "alice@example.com"
[...]

Hint: Because you supplied the `--own-key` flag, the user IDs on this key have been marked as authenticated, and this key has been marked as a fully
      trusted introducer.  If that was a mistake, you can undo that with:

  $ sq pki link retract --cert=0F761BE91983E9B50F2180CA8747303171399A43 --all

Hint: You can export your certificate as follows:

  $ sq cert export --cert=0F761BE91983E9B50F2180CA8747303171399A43

Hint: Once you are happy you can upload it to public directories using:

  $ sq network keyserver publish --cert=0F761BE91983E9B50F2180CA8747303171399A43

Please note that the hints pick up the results of the command and include them appropriately - in this case the displayed fingerprint is indeed the fingerprint of the key just generated.

Named parameter can be written like --email alice@example.com or --email=alice@example.com, allowing a = in between.

Installing sq

Linux

Install sq by using the package management of your linux distribution.

Debian

sq is part of the debian distribution since bookworm (Debian 12). Up to date versions are part of trixie (Debian 13) and following.

$ sudo apt install sq

Fedora

sq is part of Fedora 40 and following. To install sq you can use yum:

$ sudo yum install sequoia-sq

MacOSX

You have to build from source - see below.

Windows

Start by getting a decent OS from https://www.debian.org.

Install from source

sq is written in Rust. To compile it, you will need a recent rust toolchain. Your linux distribution very likely already has the relevant packages. If you don't want to use it or can't (because it's too old or you are not using linux), there is also the option to get the toolchain from the rust project directly. Look here for a more information: https://www.rust-lang.org/tools/install

Install the dependencies (bookworm, Debian 12/ Ubuntu 24.04):

$ sudo apt install git clang nettle-dev pkg-config libssl-dev capnproto libsqlite3-dev

Install the dependencies (MacOS):

If you are using homebrew, you can install the dependencies by

% brew install pkgconfig nettle openssl capnp

Install using cargo

After installing the dependencies, sq can be installed using cargo. Cargo will take care of downloading the source code and it's dependencies (only the crates). Then, cargo will compile and install the resulting binary.

$ cargo install --locked sequoia-sq

If you are using this method, you get the latest release of sq installed. If you are interested in HEAD (the current state in the git repository), please continue reading.

Get the source

Checkout the sources from the Sequoia-PGP repository at gitlab.com:

$ git clone https://gitlab.com/sequoia-pgp/sequoia-sq.git

Build the binary

Change into the project directory and build the binary:

$ cd sequoia-sq
$ cargo build --release

The result can by found in the ./target/release subfolder. Copy or soft-link it to a convenient location:

Use cargo install to compile and install in one step (recommended).

$ cargo install --locked --path .

sq will be installed in $CARGO_HOME, usually ~/.cargo/bin. For further information and options consult cargo help install.

Check your installation

A simple, "hello world"-like check is running:

$ sq version
sq 0.39.0
using sequoia-openpgp 1.21.2
with cryptographic backend Nettle 3.8 (Cv448: true, OCB: false)

Your output might be different. This check only shows that everything is in place and the binary can be executed.

Updating from source

If you installed from source, to update sq simply pull the latest changes from the repository and repeat the build. Change into the project directory and:

$ git pull
$ cargo install --locked --path .

Confidentiality

This chapter deals with subjects related to confidentiality. It contains the generation of keys and maintaining certificates. It's also about using the key material for encrypting and decryption files as well as publication and revocation of certificates.

Confidentialty - Quick start

Here you find a quick walk through on the topics of key generation and typical usages certificates.

Generating a key

To generate a key with sq, you can use the following command:

$ sq key generate --own-key --name 'alice' --email 'alice@example.com' 

Export a key from the keystore into a file

$ sq key export --cert $FINGERPRINT > $KEYFILE

Import a key into keystore

If a key is only available as a file, it can be imported into the keystore:

$ sq key import $KEYFILE

Encrypt and decrypt a file

To encrypt a message or a file with another person's certificate, you can use 'sq encrypt' as it is shown here:

$ sq encrypt --for-email alice@example.com message.txt

To decrypt a file using a key in the keystore, you can use 'sq decrypt' as follows:

$ sq decrypt message.pgp

Key generation

Generate a key

You can generate a key with different parameters and for different purposes. The default settings include an expiration of 3 years and elliptic curves as cryptographic algorithm. All of them can be modified.

Just a quick note at this point: It is not possible to explicitly generate a certificate. You only ever generate a key, as an certificate is always a part from a key, containing only public key material.

The sq key generate is a stateful operation, which imports the key directly into the key store. If you want to avoid this, you could also use the --output option to specify a location for the key file. The co-generated revocation file will automatically be stored in $HOME/.local/share/sequoia/revocation-certificates (see chapter 'files' for more information ) - as long as you don't state otherwise.

You don't have to separate different User IDs, but could instead combine them to one statement --userid 'alice <alice@example.com>'. However, this is not the recommended practice, instead Sequoia suggests to have separate User IDs for name and email address, which allows them to be certified or being revoked separately.

$ sq key generate --own-key --name alice --email alice@example.com 

This example generates a key with the two User IDs "alice" and "alice@example.com". --own-key tells sq to promote the new key as an unconstrained trust introducer. If you plan to share the key (for instance to use it as a group key), use --shared-key instead - this way the new key will not be made a trust introducer.

You can use sq pki link {add | authorize | retract} to change the trust introducer state at a later time.

For understanding in detail what sq pki link does, see chapter 'Authenticating certificates'.

Choosing a cipher-suite

The default cipher suite that sq uses when generating a key is cv25519. To select a specific suite, use --cipher-suite with one of the following options:

  • rsa2k RSA with 2048 bits
  • rsa3k RSA with 3072 bits
  • rsa4k RSA with 4096 bits
  • cv25519 Elliptic curve of the same name with 256 bits

To show it with an example:

$ sq key generate --own-key --name alice --email alice@example.com  --cipher-suite rsa4k
Opting out password protection

The default settings for generating a key include password protection for the key material, which is queried after entering the sq key generate command. In order to create a key without password protection, you have to specify the --without-password option.

$ sq key generate --own-key --name alice --email alice@example.com --without-password 
Choose expiration time

The default setting is an expiration time of 3 years. To define a different one, you can either choose any ISO 8601 string or a custom duration using N[ymwds] (both with a possible reference time using --time). You can also change the expiration date at a later point to prolong or shorten the period of time. See 'Updating keys' down here in the chapter for more information. For more thoughts on why setting an expiration date is a useful thing see key expiration.

$ sq key generate --own-key --name alice --email alice@example.com --expiration 2y

Note: All of the key generating options showed above (and more) can be combined as follows:

$ sq key generate --own-key --name alice --email alice@example.com --expiration 2y --cipher-suite rsa4k

Maintaining a key

It's possible to change certain settings of already created key material, such as updating the expiration time or adding a User ID. Others like for example the cipher suite are set once and can't be updated later.

Adding a User ID

If you want to add a User ID like an additional name and/or another email address to a certificate, sq key userid add is the subcommand to use:

$ sq key userid add --cert $FINGERPRINT --email alice@work.example.com --name alice_at_work

Note that if you accidentally specified and published a wrong User ID and want to remove it, you have to revoke the certificate. There is no other way to get rid of it, as stripping a User ID only works on locally stored certificates, not on certificates on keyservers.

Change expiration date

To change the expiration time, you can use the sq key expire subcommand:

$ sq key expire 2y --cert $FINGERPRINT

Note: This command does not change the associated subkeys.

If you instead or additionally want to change the expiration of a subkey, choose the sq key subkey expire subcommand as follows. Note that --key requires the fingerprint of the subkey you want to change and --cert the fingerprint of your primary certificate.

$ sq key subkey expire never --key $SUBKEY_FINGERPRINT --cert $FINGERPRINT

Retracting a key

A key has a certain lifespan, outside of which it is no longer valid. This either can be the case when you don't want to extend the expired key because you no longer want to use it, or if you want to terminate the expiration time prematurely. In a more severe case, you have to end it because you lost the key or it has been compromised.

Since you not only use the key yourself, but in most cases also have given the certificate - the public part of the key - to other people or uploaded it to keyservers, you would have to revoke it.

This is because it's important to let the world know about the invalidity, to prevent future usage such as encrypting data with that certificate. Otherwise people would still use the certificate to encrypt messages, which then could not be decrypted, or, in case of compromise, someone else might be able to read it.

Note: The expiration of the certificate does not affect the secret key material, encrypted data can still be decrypted.

Hard and soft revocation

Revocation is done by creating a revocation certificate and publishing this or your revoked certificate to the keyservers. A revocation certificate is stand-alone, so you can, but don't have to add it to a key to publish it. The keyservers would add it to the origin certificate and people will get this revoked certificate from there. Nevertheless, sq key revoke will automatically mark your own key as revoked while creating the revocation certificate, so you don't have to apply it and can just disseminate your updated certificate. If your certificate is not published on keyservers, but only passed by lets say email, you could either simply send the revocation certificate itself to somebody to import it (importing will automatically add it to the certificate) or you could send the already revoked certificate.

There are two different ways a revocation can be looked at. They concern the validity of signatures and certifications created by the revoked key. If the key got compromised, meaning an attacker got control over the secret key material, new signatures/certifications could be created by the attacker (and probably even dated back in time). This implies that signatures and certificates made by a compromised key cannot be trusted (even if they have been made before the compromise).

But keys do not have to be compromised to be revoked, keys can also be retired or superseded - the secret key material in this case would still be under the sole control of the keyholder. Signatures and certifications keep their validity.

So there are two classes of revocations. The revocation in case of a compromise that invalidates signatures and certifications is call "hard". The other - the retirement case - is called "soft".

The revocation certificate which is generated at creation time of the key is an emergency measure in case you lost your key. That's unrelated to any possible breach. This certificate has been stored in the $HOME/.local/share/sequoia/revocation-certificates (unless stated otherwise as described below) and it is tagged as 'unspecified' in the revocation certificate, which cannot be changed later on. If you still have access to your key (even compromised), you can (and should) generate a more meaningful revocation certificate.

In both cases you have the possibility to write the revocation certificate to a file. In the case of the emergency revocation certificate the option '--rev-cert' followed by a file name has to be provided while generating your key. It then can be copied to another data store so that you can still access it, even if your key on your computer is not available anymore. When creating a soft revocation certificate, for example in order to have a more specified one prepared for future usage, you would have to use the '--output' option to write that revocation certificate to a file instead of importing it directly into the keystore, which would happen, if you don't use this option. In that case your key would automatically be revoked by sq. If your storing it as a file, you would have to import it into the keystore to add it to the key or publish it by itself as described below.

Creating and publishing a revocation certificate for soft revocation

As described above you can generate a revocation certificate for a certificate using the command sq key revoke.

In the following example --cert requires the fingerprint of the cert to be revoked. The last two options <REASON>, where to choose from compromised, superseded, retired or unspecified, and <MESSAGE> are mandatory.

$ sq key revoke --cert $FINGERPRINT --reason retired --message 'quit my job'

This command does not give any output. If you have a look into the certificate using the origin fingerprint, you will see that is is marked as revoked. The revocation certificate has been created and at the same time imported into the keystore and applied on the key, so that the inspection shows the certificate which is marked as revoked:

sq inspect --cert $FINGERPRINT
OpenPGP Certificate.

    Fingerprint: $FINGERPRINT
                 Revoked:
                  - Retired
                    On: 2024-12-05 13:57:43 UTC
                    Message: "quit my job"

[...]

To create a revocation certificate for later usage, use the --output switch as follows:

$ sq key revoke --cert $FINGERPRINT --reason $REASON --message $MESSAGE --output $FILE

This stores the revocation certificate in a file - but does not change the key, it's still not revoked! To use this revocation cert, import it:

$ sq cert import $FILE

then the key is revoked.

Publishing

After creating the revocation certificate, you should publish the revoked certificate on the keyservers:

$ sq network keyserver publish --cert $FINGERPRINT

As described in the beginning of this chapter, you can also publish the revocation certificate itself if you saved it in a file:

$ sq network keyserver publish FILE 

Publishing is dealt in this chapter

Revoke a User ID

It's also possible to revoke a User ID such as a name or an email address using the subcommand userid. The process is very similar to the process of generating and publishing a revocation certificate:

$ sq key userid revoke --cert $FINGERPRINT --userid 'alice' --reason retired --message 'changed my name'
$ sq inspect --cert $FINGERPRINT
OpenPGP Certificate.

[...]

         UserID: alice
                 Revoked:
                  - User ID information is no longer valid
                    On: 2024-10-03 06:20:09 UTC
                    Message: "changed my name"
[...]
$ sq network keyserver publish --cert $FINGERPRINT 

Delete a key

There are more specific use cases in which someone wants to keep the certificate valid, but the secret key material should be deleted.

If you for example work in stateless mode and manage keys only in files, the way to extract the certificate from a key would be to delete the secret key material from that file(in case you want to use both of them afterwards it's necessary to make a copy of the key beforehand). A second use case could arise during the process of a (sub)key rotation. It would improve confidentiality to delete the secret key material for the sake of not being able to become infiltrated at some point in the future, which would otherwise effect previous sent and stored messages.

For this cases, sq offers the command sq key delete to delete the secret key material from a key, what remains is the certificate:

$ sq key delete --cert $FINGERPRINT

Also possible is to provide the User ID that includes a specific email address, which should be done carefully if there exist more than one key containing this User ID:

$ sq key delete --cert-email alice@example.org

Key import and export

Import a key

To import a key from a file into the keystore, you just have to use the following command:

$ sq key import $KEYFILE

$KEYFILE can contain more than one key, sq key import will import all keys it finds, skipping any certificates also in this file.

Export a key

To export a key from the keystore into a file to for instance create a backup or import it into another software like Thunderbird, this is the suitable command:

$ sq key export --cert $FINGERPRINT > $KEYFILE

or

$ sq key export --cert $FINGERPRINT --output $KEYFILE

You can also export a special subkey instead of the complete material of a key. For this you can use sq key subkey export:

$ sq key subkey export --cert $SUBKEY_FINGERPRINT > $KEYFILE

Encrypt and decrypt a file

Encryption

sq encrypt takes data from a file or from STDIN and encrypts it using key material from certificates passed to it.

If you encrypt a file for someone else's User ID and want to be able to read it afterwards, to also add your own User ID.

Certificates for encryption - the recipients - can be selected by:

  • --for $FINGERPRINT - select the certificate identified by $FINGERPRINT
  • --for-email $EMAIL - select all certificates with User IDs containing $EMAIL
  • --for-userid $USERID - select all certificates with User ID $USERID
  • --for-file $FILE - use the certificates in $FILE

One thing to keep in mind: If you use --for-email or --for-userid, sq only considers certificates which are authenticated. If you want to use an unauthenticated certificate, you can use the fingerprint as selector (as fingerprints are self-authenticating) or --for-file.

$ sq encrypt --for-email alice@example.com message.txt --output message.pgp

This encrypts the file message.txt using any certificate containing the email alice@example.com, the result is written to message.pgp. Without --output the encrypted file is printed to STDOUT.

$ sq encrypt --for $FINGERPRINT message.txt --output message.pgp

Does the same, but selects the certificate used for encryption by its fingerprint.

You can create an encrypted file using just a password by providing --with-password - sq will prompt you for the password.

All this can be combined:

$ sq encrypt --for $FINGERPRINT \
    --for-email alice@example.com \
    --for-userid "Bob Example" \
    --with-password \
    message.txt --output message.pgp

The input - the message to encrypt - does not have to be in a file. If the file is missing in parameter list, the message is taken from STDIN.

$ echo "Hello world" | sq encrypt --for $FINGERPRINT
-----BEGIN PGP MESSAGE-----

wV4D+zMBYd4zQtASAQdAM/WW6LvAEEc7SdDEYgo0s38DtywJEB5A8XIt1JhzbTcw
WMqpUI3xbb4ZBqWK9R8/DyIAOqAO1rH55vkdU63OTkj4WKo6f6c8lfMxD8JvYaGV
0j0BMEm+mp706Kpg2Ac/f3Hdn9IHb+jbeCUH/Rem2y+Wr9PrOPyL6vc1MFhCTrd+
9a2XDB3avQcYruJBSxmL
=IX5I
-----END PGP MESSAGE-----

Encrypt and sign

When encrypting a message, adding a signature works as follows:

sq encrypt --signer $FINGERPRINT --for-email alice@example.com`

or --signer-file $FILE if the signing key is in a file.

Decryption

Decrypting an encrypted file and writing it to a file works as follows:

$ sq decrypt message.pgp --output message.txt

As the encrypted message (usually) contains the ids used during encryption, decryption needs no further help to select the right key.

Generating subkeys and keys for special purposes

Adding subkeys to a certificate

Generating new subkeys

sq provides the possibility of generating additional subkeys for specified purposes and adding it to an existing certificate. The sq key subkey add command will generate and add the new subkey to the certificate both in once.

In contrast to generating a primary key, the capabilities of a subkey need to be determined explicitely. Depending on the purpose the subkey is to fulfill, it has to be equipped with the corresponding capabilities such as signing (--can-sign), authentication (--can-authenticate) and encryption type (see example below).

The default setting is to create a new subkey that is password protected, which is queried interactive and may differ from the password of the existing primary key. Nevertheless, it is also possible to specify the option --without-password.

The determination of the expiration date is also slightly different. While a primary key - unless otherwise specified - gets assigned a default value of 3 years, the subkey automatically inherits the expiration time of the associated primary key, unless one defines a different value using the option --expiration. The reference time can be changed by passing the --time argument.

Here is an example of the usage of the sq key subkey add command:

$ sq key subkey add --cert $FINGERPRINT --can-encrypt 'transport'

Note: Other values for --can-encrypt are 'storage' and 'universal', the latter being the default.

To see the result, just have a look at the certificate to which the subkey was added. It should be listed together will all other subkeys.

$ sq inspect --cert $FINGERPRINT`

Binding a subkey to another certificate

In addition to the option of generating new subkeys and attaching them to a certificate, you can bind an existing subkey (or key) to another certificate than the original one. This can be the need, for example, if you want to continue using an old subkey, but want to retire the associated primary key. Note that the subkey also remains linked with the original key as long as you don't revoke it.

Here is how it is done:

$ sq key subkey bind --key $KEY_TO_BE_BINDED_FINGERPRINT --cert $FINGERPRINT
 

Generating keys for special purposes

Per default sq generates a key that is usable for certification as well as for signing, authentication and encryption.Nevertheless, there is also the option to generate keys with limited functionalities. Depending on what purpose the key is supposed to serve, you have to either opt out the respective other features or specify the feature in more detail. There is also the possibility to generate subkeys for specified purposes and add it to the existing primary key, which is shown in the second part of this chapter. The following example shows how to generate a key for certification only. Further options, also combinations of them, can be found using sq key generate --help.

$ sq key generate --own-key --email=alice@example.com --cannot-sign --cannot-authenticate --cannot-encrypt
Please enter the password to protect key (press enter to not use a password): 
                                                  Please repeat the password: 
Certifying "<alice@example.com>" for 565C0F136EA97A9E19436CD67D697CFD08BBC29B.

Transferable Secret Key.

      Fingerprint: 565C0F136EA97A9E19436CD67D697CFD08BBC29B
  Public-key algo: EdDSA
  Public-key size: 256 bits
       Secret key: Unencrypted
    Creation time: 2024-12-05 10:03:50 UTC
  Expiration time: 2027-12-06 03:30:11 UTC (creation time + 2years 11months 30days 9h 16m 45s)
        Key flags: certification

           UserID: <alice@example.com>


Hint: Because you supplied the `--own-key` flag, the user IDs on this key have been marked as authenticated, and this key has been marked as a fully
      trusted introducer.  If that was a mistake, you can undo that with:

  $ sq pki link retract --cert=565C0F136EA97A9E19436CD67D697CFD08BBC29B --all

Hint: You can export your certificate as follows:

  $ sq cert export --cert=565C0F136EA97A9E19436CD67D697CFD08BBC29B

Hint: Once you are happy you can upload it to public directories using:

  $ sq network keyserver publish --cert=565C0F136EA97A9E19436CD67D697CFD08BBC29B



Authenticity

This chapter covers certificates, especially their application in the realm of authenticity. Creating and verifying certifications and signature, revokation of certificates, publish and retrieving and other aspects of managing certificates.

Quick start

This is an overview over operations concerning authenticity. It is by no means complete, but might give you a first orientation.

Getting a certificate from the internet

$ sq network search $QUERY

Search default keyservers, WKDs and DNS servers for certificates with User IDs or fingerprints matching $QUERY.

Publish a certificate

$ sq network keyserver publish --cert $FINGERPRINT

Publish the certificate with fingerprint $FINGERPRINT on the default keyservers.

Authenticate a certificate

sq only uses authenticated certificates. That means that certificates can only be designated by a User ID if the binding between this User ID and a certificate is marked as valid. This doesn't apply if you select a certificate by fingerprint (or use from a file), as fingerprints are regarded as self-authenticated. To mark a binding as authenticated use:

$ sq pki link add --cert $FINGERPRINT --userid $USERID

This only authenticates this specific User ID, other User IDs of the certificate are not effected. Use:

$ sq pki link add --cert $FINGERPRINT --all

as a convenience to authenticate all User IDs in a certificate in one go.

Retract authentication from a certificate

To reverse an authentication use:

$ sq pki link retract --cert $FINGERPRINT --userid $USERID

or the following to retract any associated links of a certificate:

$ sq pki link retract --cert $FINGERPRINT

Import a certificate from a file

$ sq cert import $FILE

Export a certificate to a file

$ sq cert export --cert $FINGERPRINT

Certifying a certificate

also known as "signing a key":

$ sq pki vouch certify --certifier $MY_FINGERPRINT --cert $OTHER_FINGERPRINT --userid $USERID

This way the binding between $OTHER_FINGERPRINT and $USERID is certified as authentic by the certificate $MY_FINGERPRINT. Don't forget to publish your newly created certification.

Approving a certification

To avoid flooding of certificates with bogus certifications, keyservers might insist on an approval by the keyholder of the certified certificate. To approve all pending certifications:

$ sq key approvals update --add-all --cert $FINGERPRINT

Verify a data signature

To verify a detached signature use:

$ sq verify --signature-file $DETACHED_SIGNATURE_FILE $FILE

To verify a signed message use:

$ sq verify $FILE

Please note that for a successful verification the signing certificate has to be authenticated.

Sign files and messages

$ sq sign --signer $FINGERPRINT $FILE

Sign a file using the key with fingerprint $FINGERPRINT.

Sign with detached signature

$ sq sign --signature-file --signer $FINGERPRINT $FILE

The detached signature will be printed to STDOUT.

Authenticating certificates

In case you ever want to send an encrypted email to someone, you will need public key material to do the encryption. Public key material is part of a certificate, getting the right material is equivalent to getting the right certificate. Certificates also contain User IDs, claiming that the corresponding user published this certificate and that the public key material within is indeed the right one to use. This suggests that once you know the ID of a user (for instance an email address), identifying the right certificate should be easy.

User IDs however are just claims. Claims which need to be verified before it's advisable to use any public key material. This process of verification is called authentication. This process however is blurry - how much "evidence" do I need to rely on the claimed binding between a user id and the public key material?

In case the intended receiver of my email created and published a certificate, there exists a "right" certificate. Certificates have unique, unambiguous identifiers called fingerprints. In contrast to User IDs, these are not claims but checksums over (some of) the content. Knowing the fingerprint allows to identify a certificate with certainty.

This shifts the problem from identifying the right certificate to identifying the right fingerprint, fingerprints however are much smaller - small enough to for instance print on a business card. The downside of fingerprints is that they are completely unintuitive sequences of characters with high entropy and no redundancy - they have no resemblance with a User ID.

Identifying a certificate - the waterproof way

Assuming that you are certain to have the right fingerprint - lets name it $FPR. Retrieving the corresponding certificate can be done with:

$ sq network search $FPR

This downloads the certificate from sources in the internet and stores it in the local certificate store. More details on retrieving can be found here.

The next step is to tell Sequoia PGP that the binding between a User ID and this certificate is valid. This might come as a surprise as we skip the manual comparison of fingerprints - let sq do the job:

$ sq pki link add --cert $FPR --userid $USER_ID

Since sq network search $FPR retrieved a certificate with that fingerprint, all what is left to do is to verify if this certificate contains the wanted User ID. sq pki link add does that and will return an error, if that User ID is not present (or you made a typo in the fingerprint).

After this step everything is set up to proceed with the encryption of the email.

By the way - you can get the fingerprint of your own key by

$ sq pki list $USER_ID

Identifying a certificate - softer approaches

The scenario in the preceding chapter is a bit idealistic - it assumes that

  • you are in possession of the right fingerprint
  • the corresponding certificate has been published on a well known server in the internet

Usually circumstances are less optimal. But, however you got the fingerprint (or certificate), this happened in a context which can be taken into account - used as evidence.

If you got a fingerprint printed on a slip of paper handed over by the alleged creator of the corresponding key, there is high evidence that you got the right fingerprint. Same could be said if you got the certificate itself on a usb stick.

Things become less reliable if the fingerprint reached you in an email, especially if that email is not signed. If that email came as response to a request ("Please send me your certificate ...") it adds to it's trustworthiness. If you even know the sender personally this might be another plus.

Some keyservers require an attestation. They send an email to each User ID in a certificate which looks like an email address, containing a link. Clicking that link leads to sending a specific request back to the server which is taken as a confirmation of the authenticity of the User ID - certificate binding. If you get a certificate from such a server you can take this into account.

Some websites publish alongside their contact email address the corresponding fingerprint or even the certificate. Assuming that only a limited number of people are able to modify the content of this website and all of them have honest intentions, this can be taken as evidence of authenticity.

However, all the above examples (and there are many more) are circumstantial. They reflect social relationships, assumptions on integrity and diligence and probably more.

On top of this: Not every email is send in a life or death (or prison) situation. Many of them are quiet mundane, for some it might be even acceptable to send them unencrypted.

All of this makes trade offs a viable option. It affects the amount of evidence one wants to see before relying on a certificate. These trade offs are probably the main way how "authentication" is handled.

Using the result

Once you are willing to rely on a certificate, you have to add a link in the PKI of Sequoia PGP. This enables Sequoia PGP to remember your decision and treat the certificate as authenticated from that moment onward.

Adding a link is done by

$ sq pki link add --cert $FPR --userid $USER_ID

Alternatively to --userid also --email would work. If instead you specify --all, all bindings in the designated certificate will be added.

This command does several things:

It's adding a signature to the certificate. This signature indicates that you consider the binding between the certificate and the User ID authentic. Future invocations of sq (or any other software using Sequoia PGP) will recognize this signature and the implied authenticity. You can see the effect by:

$ sq pki link list --cert-email alice@example.com
 - ┌ 60B00B3173854BA69689B19CCAC5C827BE11485F
   └ "<alice@example.com>"
     - is linked

 - ┌ 60B00B3173854BA69689B19CCAC5C827BE11485F
   └ "Alice"
     - is linked

The key used to generate the signature is not an arbitrary key, but the trust root key located in the certificate store. For details see chapter Shadow CAs.

The above command will also add a trust-depth to the certificate - User ID binding. Using sq pki link add like above the trust depth will be 0, which means that the implied authenticity by the signature does not "spread out" - it's limited to exactly this binding.

A trust depth of 1 means that not only the specific binding is considered authentic, but also all certifications made by this certificate.

If the keyholder of bob@example.com is certain that the binding between a certificate and the User ID alice@example.com is authentic, he/she can certify this binding and publish the result (for details see below). If the binding above (containing bob@example.com) would have a trust depth of 1, the implied authenticity would also cover the binding with alice@example.com. The certificate of bob@example.com would serve as a trust introducer in this case. Please note, that this is completely local and can be undone by retracting the link (see below).

Following this example, a trust depth of 2 would expand the coverage to certifications alice@example.com makes. The trust depth is a counter which indicates how many hops in a certification chain will be covered by the initial assertion of authenticity. The maximum depth is 255.

The above sq pki link add with a trust depth of 1 looks like (note the authorize):

$ sq pki link authorize --depth 1 --cert $FPR --email bob@example.com
...

Certificates can have more than one User ID. Instead of treating each User ID separately - repeating sq pki link add for each of them - you can pass --all at the command line.

$ sq pki link add --cert $FPR --all

Links created by sq pki link add will not expire, this can be changed by using --expiration DATE - DATE can either by in ISO 8601 format (2024-01-01) or a time interval like 3y (3 years).

$ sq pki link add --cert $FPR --all --expiration 3y

Links can be retracted at any point in time. Use

$ sq pki link retract --cert $FPR --email alice@example.com

to retract a specific certificate - User ID binding, or

$ sq pki link retract --cert $FPR --all

as a convenience to remove all links associated with the given certificate.

The existing links within the PKI can be listed by:

$ sq pki link list
 - ┌ 042C3AA73E1566E90FDC31B05C1EA3A3B894010E
   └ "Public Directories"
     - is linked as a partially trusted CA
     - trust amount: 40

 - ┌ 4D735E0D7DDE1B338E05F2B80AF4CE6DF697FB28
   └ "<alice@example.com>"
     - is linked

 - ┌ 4D735E0D7DDE1B338E05F2B80AF4CE6DF697FB28
   └ "Alice"
     - is linked

 - ┌ D4A2E8E858B215BD4E0A775C2904DCFB85ED0E9B
   └ "<bob@example.com>"
     - is linked

 - ┌ D4A2E8E858B215BD4E0A775C2904DCFB85ED0E9B
   └ "Bob"
     - is linked

This example shows a list with 2 certificates, each of them has two User IDs. Additionally the shadow CA for "Public Directories" is displayed.

Import and export of certificates

Certificates can be disseminated in many possible ways: as download from a website, as an attachment to an email and so on. In these cases you end up with a certificate contained in a file. To use that, you have to import it into the certificate store by:

$ sq cert import $FILE

This will try to import the certificate inside $FILE. If $FILE is skipped, sq cert import expects the certificate via STDIN:

$ cat $FILE | sq cert import

Importing certificates from a file has no influence on any implied authenticity. It's included into the certificate store as such. Use sq pki link add to attest authenticity.

Certificates can be exported from the cert store via

$ sq cert export $QUERY

with $QUERY consisting of:

  • --cert $FPR - a certificate designated by its fingerprint
  • --cert-email $EMAIL - all certificates containing a user id matching $EMAIL
  • --cert-userid $USERID - all certificates containing a user id $USERID
  • --cert-domain $DOMAIN - all certificates containing a user id with an email address from domain $DOAMIN
  • --cert-grep $PATTERN - all certificates containing a user id matching $PATTERN

These queries can be combined, sq cert export will then export any certificate matching any of these queries.

$ sq cert export --cert-email alice@example.com
$ sq cert export --cert EE99C48D11A4BE940569C4B3919EA6F609043A04 --cert-domain example.com

The result of the query is printed to STDOUT.

Search a certificate in the internet

Certificates are necessary for encryption or the verification of signatures. The users of certificates are usually not the ones who create them, so there emerges the problem of how to make certificates available to interested users. Since certificates in wire format are just plain files, they can be published on webservers or send as email attachments, but these are individual solutions which differ for each certificate.

There are solutions which are more generic - servers in the internet that can be queried for certificates.

The first generation of these servers simply accept uploaded certificates and have a standardized interface to search the inventory for user ids. Anyone can upload any certificate, which makes the inventory a highly unreliable source.

Later solutions to the dissemination introduce hurdles to prevent the publishing of arbitrary certificates. As a side effect this increases the likelihood that certificates stored on these servers are authentic.

Sequoia PGP uses 4 different types of these servers:

  • SKS servers: These are "first generation" servers with unrestricted publishing.
  • Keyservers which required a confirmation. An email is send to each user id in the certificate that resembles an email address containing a link which has to be clicked to acknowledge the upload. keys.openpgp.org works this way.
  • Web Key Directories (WKD): The certificate is stored on a webserver and its URL is constructed from the User ID as a side effect WKD cannot be queried for fingerprints. WKD implies the control of a webserver related to the mail domain of the User ID.
  • DNS-based Authentication of Named Entities (DANE): Although initially not meant for OpenPGP certificates, DANE can be used for their dissemination. DANE implies control over the DNS zone file of the mail domain.

When retrieving certificates from these servers, Sequoia PGP not only stores the answer, but also it's origin. Based on the origin Sequoia PGP assigns an "authenticity value" to the certificate ranging from 0/120 (unauthenticated) to 120/120 (fully authenticated). The values add up, certificates found on different servers gain authenticity. However, there is a cap of 40/120 which cannot be surpassed by this mechanism, thus preventing fully authenticated certificates generated simply by flooding the servers. This trust signature concept comes from the RFC 9580 standard, which is replacing RFC 4880, used by OpenPGP.

Retrieving certificates

The easiest way to get a certificate is using the sq network search $USER_ID subcommand.

$ sq network search alice@example.com
Note: Created a local CA to record provenance information.
Note: See `sq pki link list --ca` and `sq pki link --help` for more information.

Importing 1 certificate into the certificate store:

  1. EE99C48D11A4BE940569C4B3919EA6F609043A04 Alice (partially authenticated, 2/120)

Imported 1 new certificates, updated 0 certificate, 0 certificates unchanged, 0 errors.

Hint: After checking that the certificate EE99C48D11A4BE940569C4B3919EA6F609043A04 really belongs to
      the stated owner, you can mark the certificate as authenticated.  Each stated user ID can be
      marked individually using:

  sq pki link add EE99C48D11A4BE940569C4B3919EA6F609043A04 --userid "<alice@example.com>"

  sq pki link add EE99C48D11A4BE940569C4B3919EA6F609043A04 --userid "Alice"

      Alternatively, all user IDs can be marked as authenticated using:

  sq pki link add EE99C48D11A4BE940569C4B3919EA6F609043A04 --all

Using sq network search this way will:

  • query all default keyservers (keys.openpgp.org, mail-api.proton.me, keys.mailvelope.com, keyserver.ubuntu.com, sks.pod01.fleetstreetops.com)
  • tries to download a certificate via WKD
  • and queries the DNS for a DANE entry

In this example sq network search found exactly one certificate, which gets stored in the local certificate storage.

To keep track of the origin, Sequoia PGP creates intermediate certificate authorities, which certify the received certificate. This is basically the mechanism by which Sequoia PGP determines implicit authenticity by origin.

Each successful attempt adds 1/120 to the "authenticity value", in this case the same certificate is found on two different keyservers, which makes 2/120.

The list of keyservers can be customized by passing --server $URI, this option can be used multiple times:

$ sq network search --server hkps://keys.openpgp.org --server hkps://my.own.keyserver.net alice@example.com

This customization however only affects the list of keyservers, WKD and DANE are still used.

Please note that server addresses passed via --server need to have their protocol specified (hkps://).

Using the --output $FILE option prevents sq from importing the certificate into the cert store but outputs to the supplied $FILE instead. In this case, sq will also consult the local cert store for matching certificates.

$ sq network search --output alice.cert alice@example.com

sq network search takes a query as parameter. In the examples above this was a User ID in form of an email address, but it can also be a fingerprint.

$ sq network search EE99C48D11A4BE940569C4B3919EA6F609043A04 

will fetch Alices certificate from the example above.

Surprising results

When querying network servers for certificates, it's possible that seemingly unrelated certificates are returned. This is especially true for WKD and DANE. sq network search will fetch these certificates, as they might be usable or even better fitting.

Please keep in mind, that fetched certificates are not authenticated automatically, so they will not undermine your security.

Fine tuning the list of sources for retrieval

sq allows you to restrict the sources it queries for answers.

  • sq network keyserver search
  • sq network wkd search
  • sq network dane search

This will limit the search to the respective sources. Keep in mind that not all sources can deal with all type of queries: WKD for instance can only be queried for User IDs in the form of email addresses.

Publish a certificate

TODO: publishing/generating with WKD and DANE is still changing.

Publishing a certificate is a bit more hands-on than retrieving them. sq can directly publish to keyservers, for other methods of dissemination sq can generate the necessary data.

The simplest way to publish to keyservers is:

$ sq network keyserver publish --cert EE99C48D11A4BE940569C4B3919EA6F609043A04

or more general

$ sq network keyserver publish $QUERY

sq searches inside the cert store for certificates matching $QUERY and publishes all results. $QUERY can be

  • A fingerprint: --cert $FINGERPRINT
  • A User ID: --userid "Alice Example"
  • An email address: --email alice@example.com
  • A file: --file $FILE

This example publishes the certificate to the default keyservers (keys.openpgp.org, mail-api.proton.me, keys.mailvelope.com, keyserver.ubuntu.com, sks.pod01.fleetstreetops.com). This list can be customized by adding --server to the command:

$ sq network keyserver publish --server hkps://keys.openpgp.org --server hkps://some.other.keyserver.tld --email alice@example.com

Please note, that --server expects the parameter to specify the protocol (eg hkps://).

Generating and publishing files for WKD

Web Key Directory (WKD) is another way of distributing certificates. It defines a scheme which translates an email address into a URL (actually there are 2 schemes). That corresponds to an accordingly configured webserver which delivers the certificates upon request.

This requires the generation of files and directories complying with the scheme. sq can help by generating the required structure.

$ sq network wkd publish --create advanced --domain example.com --file certs.cert /tmp/foo

This will create all files and directories under /tmp/foo, starting with the subdirectory .well-known. From the keyring certs.cert only certificates with User IDs in domain example.com are included.

The above command will generate a directory structure according to the 'advanced method', to be used as content for https://openpgpkey.example.com/.well-known/openpgp/.... If you need the 'direct method' (https://example.com/.well-known/openpgp/...), use --create direct at the command line.

$ sq network wkd publish --create direct --domain example.com --file certs.cert /tmp/foo

If there is already a directory structure present, using --create will return an error.

Error: Cannot create WKD because /tmp/foo already contains one

Instead of pulling the certificates from a file, you can fetch the certificates from the cert store:

  • --cert $FINGERPRINT to use a certificate by that fingerprint
  • --userid $USER_ID any certificates matching $USER_ID
  • --email $EMAIL any certificates matching $EMAIL
$ sq network wkd publish --domain example.com --email alice@example.com /tmp/foo

or even all certificates for a domain which can be found inside the cert store by skipping a filtering query.

$ sq network wkd publish --domain example.com /tmp/foo

If supplied with --rsync, sq invokes a local copy of rsync passing the destination as-is.

$ sq network wkd publish --rysnc --domain example.com alice@myserver:/tmp/foo

More on hosting a WKD: https://wiki.gnupg.org/WKDHosting

Generating records for DANE

For publishing certificates via DNS (aka DANE), a TXT record has to be added to the zone file of the mail domain.

The record can be generated like this:

$ sq network dane generate --domain example.con --email alice@example.com

The result will be printed to STDOUT.

This example will generate a TXT record in OPENPGPKEY format. If your DNS server cannot handle this type of record, you can generate a generic record by adding --type generic.

$ sq network dane generate --type generic --domain example.com --email alice@example.com

A more compact form of an OPENPGPKEY record can be generated by adding a size limit. sq will try to match that limit as best as it can.

$ sq network dane generate --size-limit 1024 sequoia-pgp.org certs.cert

More on DANE can be found here: https://datatracker.ietf.org/doc/draft-ietf-dane-openpgpkey/12/

Certificate management

Listing available certificates

Certificates are usually stored in the cert store. To list the content of this store use:

$ sq cert list

This command outputs all certificates in the store which are authenticated. sq only uses authenticated certificates for cryptographic operations.

A list of all certificates in the store is available via:

$ sq cert list --gossip

The list of certificates can be filtered by:

$ sq cert list $PATTERN

In this case, $PATTERN is just a string (in UTF-8). Each certificate which contains a User ID containing this string will be displayed.

$ sq cert list bob@example
 - 61E064A38CD0230666D40B823CB405E519E599A1
   - created 2024-10-23 09:08:22 UTC
   - will expire on 2027-10-24 02:34:43 UTC

   - [    ✓    ] <bob@example.com>

Hint: To view why a user ID is considered valid, pass `--show-paths`.

Hint: To see more details about a certificate, for example 61E064A38CD0230666D40B823CB405E519E599A1,
      run:

  $ sq inspect --cert=61E064A38CD0230666D40B823CB405E519E599A1

This is an example, where $PATTERN contains an incomplete email address, which matches one certificate.

Paths

Certificates are considered authenticated if there is a path from the "Local Trust Root" certificate. Use --show-paths to display existing paths:

$ sq cert list bob@example --show-paths
 - 259392E02F8DCC447ED77A3114A33DD1C6BD5288
   - created 2024-11-07 11:33:24 UTC
   - will expire 2027-11-08T04:59:45Z

   - [    ✓    ] <bob@example.com>

     ◯─┬ 686D08D93C582976252805A6695224B3564396B2
     │ └ ("Local Trust Root")
     │
     │  certified the following binding on 2024‑11‑07 as a meta-introducer (depth: unconstrained)
     │
     └─┬ 259392E02F8DCC447ED77A3114A33DD1C6BD5288
       └ "<bob@example.com>"


Hint: To see more details about a certificate, for example 259392E02F8DCC447ED77A3114A33DD1C6BD5288,
      run:

  $ sq inspect --cert=259392E02F8DCC447ED77A3114A33DD1C6BD5288

This example shows that Local Trust Root directly certified the binding of bob@example.com with it's certificate, when this certification was made and the assigned trust depth.

Finding certificates in the local cert store

There are further commands sq implements, which are more focused on specific operations on authenticated (directly usable) certificates

  • sq pki identify --cert $FPR shows the certificate $FPR like sq cert list $FPR does. The differences is that sq pki identify will not try to use $FPR to match User IDs.
  • sq pki lookup will explicitly interpret it's parameters as User IDs. There are --userid and --email as designators available.
  • sq pki authenticate takes a certificate and a User ID and checks if there is a binding between these in the cert store, which is authenticated.

These 3 commands can also be used on unauthentic bindings, if you pass --gossip.

$ sq pki lookup --email alice@example.com --gossip

Modifying a certificate

If you want to modify or add a User IDs or update expiration dates, you have to use the corresponding key instead. User ids and metadata like expiration dates are (self)signed by the primary key and the necessary secret key material is not part of a certificate.

After modifying your key, you have to export the certificate again. It will now contain the modifications applied to the key and can be published in the usual way.

Along the same line, certificates cannot be revoked, this also has to be done using the key.

There are ways to modify a certificate, for instance by adding a certification - but these modifications will not be self signed. The self signature is used to show that the signed component in a certificate is aligned with the intention of the keyholder.

Certify and authorize certificates

Certifying a User ID for a certificate

While sq pki link add generates a signature and adds it to the certificate, that signature is not exportable. sq cert export will skip this signature. If you want to share your attestation, you have to generate an exportable signature by using sq pki vouch certify.

Other than sq pki link add the key which creates the signature when doing sq pki vouch certify has to be passed as a parameter. The originator of the certification is an important information for others to evaluate its usefulness.

A certification is generated as follows:

sq pki vouch certify --certifier $fingerprint --cert $fingerprint --email=bob@example.com

Hint: Imported updated cert into the cert store.  To make the update effective, it has to be
      published so that others can find it, for example using:

$ sq network keyserver publish --cert=1C88780EF239586AF463758094119887B3462B88

With

  • --certifier $fingerprint being the fingerprint of alice@example.com as originator of the attestation
  • --cert $fingerprint the fingerprint of the certificate to attest
  • "bob@example.com" as User ID of the certificate to attest.

This basically says that alice@example.com is certain that the binding between 1C88780EF239586AF463758094119887B3462B88 and bob@example.com is authentic and is willing to make that attestation public. Keep in mind that publishing an attestation is an explicit step, generating a certification does not include it's publication.

sq pki vouch certify prints the resulting certificate (the original certificate with the newly created signature) to STDOUT or to a file specified by --output FILE. The modified certificate is also stored in the local certificate store and can be exported at a later time.

The certification can contain additional information or restrictions:

  • A certification created like above has a lifetime of 5 years, after that period the certification is considered as expired. Add --expiration DATE or even --expiration "never" to change this behavior. The DATE has to be in ISO 8601 format, like 2024-07-02 or a time interval like 3y (3 years).

The certificate with the new certification in it can now be disseminated - this however is not recommended. Instead send the new certificate to the respective keyholder, so that he/she can approve your attestation, basically signing your certification. See more details after the following paragraph.

Approving a certification

This sounds complicated, but it prevents attackers (or trolls) to simply add loads of certifications to a certificate, blowing it up to a size which cannot be handled anymore. For this reason, modern keyservers will filter out certifications which do not have an approval signature.

After receiving newly certified certificate, a keyholder can check that certification by saving it into a file and then inspecting, reimporting and subsequently approve that certification as follows:

$ sq inspect alice.cert  --certifications
$ sq cert import alice.cert
$ sq key approvals update --all --cert $FINGERPRINT

This will add an approval signature to all certifications in the certificate identified by $FINGERPRINT. Use --cert-file $FILE in case you have the certificate as a file and don't want to import it.

After that step the keyholder has to publish that certificate again to make it available to others.

Authorize a certificate as a trusted introducer

A trusted introducer is the equivalent of a certificate authority (CA). It expresses the certifiers trust in the certifications made by the trusted introducer / the CA to be valid. Such a certification as trust introducer has a default trust depth of 1, which can be modified by passing --depth NUMBER or even --unconstrained which doesn't impose a limit to the depth.. This is one way to restrict the depth of that certification by limitting the ability of the trust introducer to specify further introducers. Additionally such a certification can be limited to one or more domains. The trust introducer can create certifications for all kinds of domains, the before mentioned certification will restrict it's effect to the passed domains.

A certification to mark a certificate as a trusted introducer is done like this:

$ sq pki vouch authorize --certifier $fingerprint --cert $fingerprint --domain=example.com --email bob@example.com

Certifying "<bob@example.com>" for 1C88780EF239586AF463758094119887B3462B88.


Hint: Imported updated cert into the cert store.  To make the update effective, it has to be published so that others can find it, for example using:

  $ sq network keyserver publish --cert=1C88780EF239586AF463758094119887B3462B88

Verify a signature

Software distribution is often done by downloading an installer from a website. If you don't want to rely on the integrity of the website, you cannot be sure that the installer in not tempered with.

To help you asserting the authenticity of the downloaded file, the provider of the file can create a downloadable signature of it, which you can verify. A successful verification means that the downloaded file was not manipulated after the signature was created.

This tutorial contains a very verbose walk through a verification, explaining each step.

1. Getting the files

The Tails project offers an integrity check via signature, so we will use it as an example.

First, download the ISO-image and the signature from the tails website. You can use your browser or any other suitable tool. This example uses wget.

To get the software from the website, go to tails.net/install, choose your OS and follow the instructions to download tails and the OpenPGP signature.

For using wget, go to your working directory and download the files as follows (replace folder and file names with current version):

$ wget https://download.tails.net/tails/stable/tails-amd64-6.2/tails-amd64-6.2.img
$ wget https://tails.net/torrents/files/tails-amd64-6.2.img.sig

2. Inspect the signature

If you look at the directory, you can see the two files that you downloaded. The first one is the tails image and the second is the detached signature.

$ ls -l
total 1431572
-rw-r--r-- 1 alice alice 1465909248 Apr 22 12:35 tails-amd64-6.2.img
-rw-r--r-- 1 alice alice        833 Apr 23 13:20 tails-amd64-6.2.img.sig

By using sq inspect, you can now have a closer look into the signature file:

$ sq inspect tails-amd64-6.2.img.sig 
tails-amd64-6.2.img.sig: Detached signature.

Alleged signer: 05469FB85EAD6589B43D41D3D21DAD38AF281C0B, Tails developers (offline long-term identity key) <tails@boum.org> (UNAUTHENTICATED)
           Note: Signatures have NOT been verified!

What you got here is the signing key's fingerprint. Now check what the web of trust tells about this alleged signer:

$ sq network search 05469FB85EAD6589B43D41D3D21DAD38AF281C0B

Importing 13 certificates into the certificate store:

  1. 09F6BC8FEEC9D8EE005DBAA41D2975EDF93E735F Tails developers (Schleuder 
 mailing-list)
 <tails@boum.org> (partially authenticated, 1/120)
  2. 0109B6D7680FEEFDCE783EEE750AE75857622766 Tails APT repository  <tails@boum.org>
(UNAUTHENTICATED)
  3. 0D24B36AA9A2A651787876451202821CBE2CD9C1 Tails developers (signing key) <tails@boum.org> (UNAUTHENTICATED)
  4. 2ED1191631B0B60CB27DA90A4C3DB83F3F50D2D9 gpg --check-sigs A490D0F4D311A4153E2BB7CADBB802B258ACD84F <tails@boum.org> (UNAUTHENTICATED)
  5. 317026534CCC841EF92EB5D4F370463ECD68841B Tails developers <tails@boum.org> (UNAUTHENTICATED)
  6. 3E97E609FC8DAE546FB6DF005C20D5DCAECAEF90 Tails developers <tails@boum.org> (UNAUTHENTICATED)
  7. 98D080F83122CB4A3F45663825BF6AAECF914C38 Tails <tails@boum.org> 
(UNAUTHENTICATED)
  8. 9BF8721D77F0242C8A6D0507D911B4A137BD2413 Tails developers (offline long-
 term identity key) <tails@boum.org> (UNAUTHENTICATED)
  9. A490D0F4D311A4153E2BB7CADBB802B258ACD84F Tails developers (offline long-
term identity key) <tails@boum.org> (UNAUTHENTICATED)
 10. B6C645C871D595069ED1AE33DB1573A449F1F400 gpg --check-sigs
A490D0F4D311A4153E2BB7CADBB802B258ACD84F <tails@boum.org> (UNAUTHENTICATED)
 11. C3BAA4BFE369B2B86018B5150E08AC7806C069C8 BIGHEAD2 <TAILS@BOUM.ORG> (UNAUTHENTICATED)
 12. D55A59A2CAFC5EAB7AA4777010C2D872BFBAF237 Tails <tails@boum.org> (UNAUTHENTICATED)
 13. EB24960079A3E2B93BFE48B505F8BB78B38F4311 Amsesia <amnesia@boum.org> (UNAUTHENTICATED)

Imported 0 new certificates, updated 0 certificates, 13 certificates > unchanged, 0 errors.

After checking that a certificate really belongs to the stated owner, you can > mark the certificate as authenticated using:

    sq pki link add FINGERPRINT

What you can see from this result is that the 9th certificate is the one mentioned on the tails website, which is a first step in the right direction. But you can also notice that none of the enumerated certificates has the fingerprint 05469FB85EAD6589B43D41D3D21DAD38AF281C0B.

If this is the case, it is a reason to further investigate. When you have a look at the Fingerprint by using 'sq pki list', you will see that it is a subkey of the certificate that we have already noticed above:

$ sq pki list 05469FB85EAD6589B43D41D3D21DAD38AF281C0B
Certificate A490D0F4D311A4153E2BB7CADBB802B258ACD84F contains the subkey 05469FB85EAD6589B43D41D3D21DAD38AF281C0B.
A490D0F4D311A4153E2BB7CADBB802B258ACD84F will expire on 2025-01-25T09:24:54Z
  [   0/120 ] Tails developers (offline long-term identity key) <tails@boum.org>
  [   0/120 ] Tails developers <tails@boum.org>

 To view why a user ID is considered valid, pass `--show-paths`

 To see more details about a certificate, run:

  $ sq inspect --cert FINGERPRINT

 After checking that a user ID really belongs to a certificate, use `sq pki 
 link add` to mark
 the binding as authenticated, or use `sq network search FINGERPRINT|EMAIL` to 
 look for new certifications.
 

3. Verify the signature

Check the detached signature:

$ sq verify --signature-file tails-amd64-6.2.img.sig tails-amd64-6.2.img
Authenticating A490D0F4D311A4153E2BB7CADBB802B258ACD84F ("Tails developers (offline long-term identity key) <tails@boum.org>") using the web of trust:
  A490D0F4D311A4153E2BB7CADBB802B258ACD84F: "Tails developers (offline long-term identity key) <tails@boum.org>" is unauthenticated and may be an impersonation!
  A490D0F4D311A4153E2BB7CADBB802B258ACD84F: "Tails developers <tails@boum.org>" > is unauthenticated and may be an impersonation!
Unauthenticated checksum from D21DAD38AF281C0B ("Tails developers (offline long-term identity key) <tails@boum.org>")

  After checking that D21DAD38AF281C0B belongs to "Tails developers (offline 
 long-term identity key)
  <tails@boum.org>", you can authenticate the binding using:

    $ sq pki link add D21DAD38AF281C0B "Tails developers (offline long-term identity key) <tails@boum.org>"

 1 unauthenticated checksum.
 Error: Verification failed: could not fully authenticate any signatures

So far all is known is that the signature was made from the image file and the key with the fingerprint A490D0F4D311A4153E2BB7CADBB802B258ACD84F. At this point nothing is known about the authenticity. The key has bindings to the displayed User IDs - it looks authentic, but for now these are just unfounded claims.

4. Authenticate the signature

Tails suggests to import its signing key and the key of Chris Lamb from the debian keyring. The idea is that there is trust in the debian developers. Chris is one of them and he signed the tails signing key.

5. Get the signing key

Get the signing key from the tails project and import it into your local cert store:

$ wget https://tails.net/tails-signing.key
$ sq cert import tails-signing.key 
Imported A490D0F4D311A4153E2BB7CADBB802B258ACD84F, Tails developers (offline long-term identity key) <tails@boum.org> (UNAUTHENTICATED)
Imported 0 new certificates, updated 0 certificates, 1 certificates unchanged, 0 errors.

The key is already in the local cert store. This shows that the key fetched by sq network search and the one downloaded from the site are the same.

6. Export and inspect the certificate

Export Chris certificate from the debian keyring and inspect it:

$ sq cert export --keyring /usr/share/keyrings/debian-keyring.gpg --no-cert-store --userid "Chris Lamb <chris@chris-lamb.co.uk>" | sq inspect
-: OpenPGP Certificate.

    Fingerprint: C2FE4BD271C139B86C533E461E953E27D4311E58
Public-key algo: RSA
Public-key size: 4096 bits
  Creation time: 2009-07-12 19:43:47 UTC
      Key flags: certification, signing

         Subkey: 0E08C16E029D46527FA2FB4C72B3DBA98575B3F2
Public-key algo: RSA
Public-key size: 4096 bits
  Creation time: 2009-07-12 19:49:01 UTC
      Key flags: transport encryption, data-at-rest encryption

         UserID: Chris Lamb <chris@chris-lamb.co.uk>
Certifications: 28, use --certifications to list

         UserID: Chris Lamb <lamby@debian.org>
Certifications: 31, use --certifications to list

        UserID: Chris Lamb <lamby@gnu.org>
Certifications: 29, use --certifications to list

Besides other information this shows the fingerprint of the key.

7. Examine the signing key

Next examine the tails signing key with respect to certifications, especially the one found in the debian keyring:

$ sq inspect --cert A490D0F4D311A4153E2BB7CADBB802B258ACD84F --certifications | grep C2FE4BD271C139B86C533E461E953E27D4311E58

WARNING: sq does not have a stable CLI interface. Use with caution in scripts.

                 Alleged certifier: C2FE4BD271C139B86C533E461E953E27D4311E58
                 Alleged certifier: C2FE4BD271C139B86C533E461E953E27D4311E58
 

The tails signing key was certified by a key contained in the debian keyring. This gives the trust path debian keyring -> C2FE4BD271C139B86C533E461E953E27D4311E58 -> tails signing key. For a one-time verification this might be sufficient - assuming that you want to rely on the debian keyring to contain valid and authenticated keys.

For future verifications the workflow described so far can be memorized, thus saving a few steps.

8. Export certificate and import it into cert store

Export Chris certificate from the debian keyring and import it into the cert store of sequioa-pgp. This step makes future dealing with the debian keyring superflous:

$ sq cert export --keyring /usr/share/keyrings/debian-keyring.gpg --no-cert-store --userid "Chris Lamb <chris@chris-lamb.co.uk>" | sq cert import
Imported C2FE4BD271C139B86C533E461E953E27D4311E58, Chris Lamb <chris@chris-lamb.co.uk> (UNAUTHENTICATED)
Imported 1 new certificates, updated 0 certificates, 0 certificates unchanged, 0 errors.

The key - or more precise: the certificate of the key - is now in the cert store. It's still unauthenticated, meaning that the bindings to User IDs, which are contained in the certificate, are still treated as unsubstantiated claims.

9. Assigning reliance on the validity of the key

Assuming that the bindings in the certificate are valid, adding a link between the certificate's fingerprint and a User ID will store this assumption in the cert store.

It's possible to explicitly name the User ID that should be linked, or pass --all to link all User IDs within the certificate in one step.

$ sq pki link add C2FE4BD271C139B86C533E461E953E27D4311E58 --all
Linking C2FE4BD271C139B86C533E461E953E27D4311E58 and "Chris Lamb <chris@chris-
lamb.co.uk>".

Linking C2FE4BD271C139B86C533E461E953E27D4311E58 and "Chris Lamb
<lamby@debian.org>".

Linking C2FE4BD271C139B86C533E461E953E27D4311E58 and "Chris Lamb
<lamby@gnu.org>".

The tails signing key contains a certification by Chris. What is still missing is the information that certifications made by Chris should be honoured. Without that, the certification has no special meaning and will be ignored.

10. Mark certificate as a trusted introducer

Marking a certificate as a trust introducer will make certifications created by the corresponding key effective. Certificates containing a certification by this key will be treated as authenticated.

The trust introducer acts as a certification authority (CA). Sequoia-PGP allows to restrict the range of domains for which the trust introducer will be regarded as authorative. Certifications made for certificates of domains that are not in this range will be ignored.

The range of domains is passed via --ca when adding a link with sq pki link add:

$ sq pki link authorize --domain boum.org --cert C2FE4BD271C139B86C533E461E953E27D4311E58 --all

11. Check the authentication

To check whether sequoia-pgp regards a binding as authenticated, you can use sq pki authenticate:

$ sq pki authenticate A490D0F4D311A4153E2BB7CADBB802B258ACD84F --email tails@boum.org
A490D0F4D311A4153E2BB7CADBB802B258ACD84F will expire on 2025-01-25T09:24:54Z
  [    ✓    ] Tails developers (offline long-term identity key) <tails@boum.org>
  [    ✓    ] Tails developers <tails@boum.org>

To view why a user ID is considered valid, pass `--show-paths`

To see more details about a certificate, run:

  $ sq inspect --cert FINGERPRINT

Adding --show-paths will print out more information, especially the trust path which makes the certificate considered as authentic:

$ sq pki authenticate A490D0F4D311A4153E2BB7CADBB802B258ACD84F --email tails@boum.org --show-paths
[✓] A490D0F4D311A4153E2BB7CADBB802B258ACD84F Tails developers (offline long-term identity key)
    <tails@boum.org>: fully authenticated (100%)
  ◯ C746308CCC319B78998247210B986BAF950E297A ("Local Trust Root")
  │   certified the following certificate on 2024-05-07 as a fully trusted meta-introducer (depth:
  │   unconstrained)
  ├ C2FE4BD271C139B86C533E461E953E27D4311E58 ("Chris Lamb <chris@chris-lamb.co.uk>")
  │   certified the following binding on 2020-03-19
  └ A490D0F4D311A4153E2BB7CADBB802B258ACD84F "Tails developers (offline long-term identity key)
    <tails@boum.org>"

[✓] A490D0F4D311A4153E2BB7CADBB802B258ACD84F Tails developers <tails@boum.org>: fully authenticated
    (100%)
  ◯ C746308CCC319B78998247210B986BAF950E297A ("Local Trust Root")
  │   certified the following certificate on 2024-05-07 as a fully trusted meta-introducer (depth:
  │   unconstrained)
  ├ C2FE4BD271C139B86C533E461E953E27D4311E58 ("Chris Lamb <chris@chris-lamb.co.uk>")
  │   certified the following binding on 2020-03-19
  └ A490D0F4D311A4153E2BB7CADBB802B258ACD84F "Tails developers <tails@boum.org>"

12. Verify the downloaded file (again)

With everything in place, verifying a file with a detached signature is simply:

$ sq verify --signature-file tails-amd64-6.2.img.sig tails-amd64-6.2.img
Authenticating A490D0F4D311A4153E2BB7CADBB802B258ACD84F ("Tails developers (offline long-term
identity key) <tails@boum.org>") using the web of trust:
  Fully authenticated (120 of 120) A490D0F4D311A4153E2BB7CADBB802B258ACD84F, Tails developers
  (offline long-term identity key) <tails@boum.org>
    ◯ C746308CCC319B78998247210B986BAF950E297A ("Local Trust Root")
    │   certified the following certificate on 2024-05-07 as a fully trusted meta-introducer (depth:
    │   unconstrained)
    ├ C2FE4BD271C139B86C533E461E953E27D4311E58 ("Chris Lamb <chris@chris-lamb.co.uk>")
    │   certified the following binding on 2020-03-19
    └ A490D0F4D311A4153E2BB7CADBB802B258ACD84F "Tails developers (offline long-term identity key)
      <tails@boum.org>"

  Fully authenticated (120 of 120) A490D0F4D311A4153E2BB7CADBB802B258ACD84F, Tails developers
  <tails@boum.org>
    ◯ C746308CCC319B78998247210B986BAF950E297A ("Local Trust Root")
    │   certified the following certificate on 2024-05-07 as a fully trusted meta-introducer (depth:
    │   unconstrained)
    ├ C2FE4BD271C139B86C533E461E953E27D4311E58 ("Chris Lamb <chris@chris-lamb.co.uk>")
    │   certified the following binding on 2020-03-19
    └ A490D0F4D311A4153E2BB7CADBB802B258ACD84F "Tails developers <tails@boum.org>"

  Good signature from D21DAD38AF281C0B ("Tails developers (offline long-term identity key)
  <tails@boum.org>")

1 good signature.

Addition

Verify a signature that is not detached is very similar to the command described in paragraph 3. Instead of explicitly specifying the file name of the signature hash, only the file that was signed is specified.

$ sq verify signed_file.pgp

Note that technically it's also possible to skip the automatic check of authentication while verifying a file. This in done by specifying the signer certificate as a file instead of using an imported certificate. This method is only safe if you are sure the certificate in the file you are using is authentic.

$ sq verify --signer-file alice.cert file.txt

To verify a detached signature:

$ sq verify --signer-file alice.cert --signature-file file.sig file.txt

Signing files and messages

Signing files and/or messages means creating a signature over data. There are two ways to store the newly created signature:

  • by wrapping the file in an OpenPGP message structure which includes the signature
  • by creating a detached signature within its own file, leaving the signed data untouched

The first option has the advantage that everything is in one file. The advantage of the second option is that the signed file doesn't change, so that it can be used without unwrapping the OpenPGP message structure first.

Creating an inlined signature

$ sq sign --signer $FINGERPRINT $FILE

In this example a signature is created over the content of $FILE file using the key designated by $FINGERPRINT. Instead of using the data from a file, sq sign can also take data from STDIN.

$ echo "my message" | sq sign --signer $FINGERPRINT

The output of this operation is printed to STDOUT.

$ echo "my message" | sq sign --signer $FINGERPRINT
-----BEGIN PGP MESSAGE-----

xA0DAAoWQeEtk/c7kG4Byw9iAAAAAABleGFtcGx0ZQrCvQQAFgoAbwWCZyt6wAkQ
QeEtk/c7kG5HFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3Jn
72xkqs1135T2u5oIlngq51GwLmFm8jevOh4nssMT/WMWIQTlcn7y4+W/syeiLW1B
4S2T9zuQbgAA4VgBAK5XsyCTIA1VrZQYkKm7BpygYnco7K+IrWFR9ePczM3BAP9j
6V37oWwULdWG3vZsIweDNbjWfHeblOQzajAFjDEWDA==
=HkKe
-----END PGP MESSAGE-----

The output can either be redirected to a file by using > or by specifying --output $NEW_SIGNED_FILE.

Instead of using a key from the keystore (via --signer), a file containing a key can be used: --signer-file $KEYFILE.

Creating a detached signature

$ sq sign --signer $FINGERPRINT --signature-file $FILE  
-----BEGIN PGP SIGNATURE-----

wr0EABYKAG8FgmcrfMgJEEHhLZP3O5BuRxQAAAAAAB4AIHNhbHRAbm90YXRpb25z
LnNlcXVvaWEtcGdwLm9yZ9pEw/OyHXskP8ODrJIZdpKXKXa4cJdbYSnAYuevHk1j
FiEE5XJ+8uPlv7Mnoi1tQeEtk/c7kG4AABr1AP9H0PDDa6TH5ocDtrpxPuPa3Abq
VnWu8rw1pMaW7G1aHwD/RCxGUGskETDDRXmK4Sfl8JeqoKABEWXi9w6HaQD7SAA=
=nZsK
-----END PGP SIGNATURE-----

This time only the newly generated signature is printed to STDOUT, $FILE is left untouched. As with inline signing you can use --signer-file and --output.

Technical

This chapter describes more technical use cases.

Configuration

The behavior of sq is configurable using configuration files. There is the configuration for the cryptographic policy and the configuration for sq. The configuration for the cryptographic policy is used by Sequoia PGP and thus determines the behavior of sq concerning cipher algorithms, hashes and the like (for details see below).

There is a second file configuring sq: Selection of default keyservers, default expiration times for newly generated keys, default ciphers, etc. Additionally this configuration allows to override the settings for the cryptographic policy.

The cryptographic policy configuration is located in /etc/crypto-policies/back-ends/sequoia.config. The configuration for sq in ~/.config/sequoia/sq/config.toml.

Getting configuration settings

sq has a subcommand config to access configuration settings.

$ sq config get

Will read out the complete configuration of sq or specify a key to selectively retrieve the corresponding value.

$ sq config get key.generate.cipher-suite
key.generate.cipher-suite = "cv25519"

If you are interested in more than the plain value, but want a hint on what a specific setting is used for, you can use sq config inspect.

  • $ sq config inspect paths
    
    This gives you pathes to the different files or directories sq uses: key and cert store, as well as configuration files
  • $ sq config inspect network
    
    Tells you which services sq will use if it's performing a network search.
  • $ sq config inspect policy
    
    Gives hints about the currently active cryptographic policy.

To create a new config file to tune your setup, you can generate one based on your current setting by

$ sq config template

The generated configuration will be printed to STDOUT or into a file if you specify --output $FILE. Move this output to ~/.config/sequoia/sq/config.toml, so that sq can pick it up. This configuration allows you to also modify the cryptographic policy.

Cryptographic Policy Configuration

Sequoia PGP has a StandardPolicy that defines, which algorithms (ciphers, hash functions, etc.) are valid and available. This policy can be adjusted to care for specific needs.

The adjustments are configured in a file (command line switches are not available), by default located in /etc/crypto-policies/back-ends/sequoia.config. This location can be changed by setting the environment variable SEQUOIA_CRYPTO_POLICY. A missing configuration file simply means "no adjustments" and the default policy applies.

These are global adjustments, effective for every user on the system. Individualized adjustments can be made in the user configuration file.

Sequoia PGP comes with a sensible default cryptographic policy. There is no safety net when you modify it's settings! You could introduce unsafe behavior or stop Sequoia PGP from working at all.

Format

The configuration file uses the TOML Format. It consists of the following sections:

  • hash_algorithms
  • asymmetric_algorithms
  • symmetric_algorithms
  • aead_algorithms
  • packets

Missing or empty sections again mean "no adjustments".

A simple adjustment might look like this:

[hash_algorithms]
sha1 = "never"

This advises Sequoia PGP to never use or accept SHA-1 hashes. Signatures based on SHA-1 would be considered "invalid". Since signatures play a central role, this might also invalidate some certificates and keys.

Besides never and always, adjustments can have a date value. This specifies a cutoff time after which the adjustment would switch from always to never.

[hash_algorithms]
sha1 = 2010-01-01 

The format of the configuration file allows to use keys which are not (yet) defined. This way adjustment can be made for algorithms which will be included in a foreseeable future. To avoid parsing errors, these future keys have to be declared by using ignore_invalid.

This example configures the nonexisting hash function "SHA-4" as "always valid" while declaring it as a future key, so that versions of Sequoia PGP, which do not know about SHA-4, can still parse the configuration.

[hash_algorithms]
sha4 = "always"
ignore_invalid = ["sha4"]

Please note that ignore_invalid has no influence on the crypto policy itself, it's only meant to support the parser.

If for some reason only a fixed set of algorithms should be considered valid, there is a way to prevent algorithms introduced by upgrades to the software to take effect. The "catch all" key is default_disposition. The following example allows SHA256 and forbids everything else:

[hash_algorithms]
sha256 = "always"
default_disposition = "never"

Hash algorithms have properties which can be configured individually. second_preimage_resistance and collision_resistance address attacks on hash functions.

[hash_algorithms]
sha1.second_preimage_resistance = 2030-01-01
sha1.collision_resistance = 2022-01-01

The packets section allows configurations for different versions of a packet type. The following example sets (different) cutoff times for signature packets in version 3 and 4, while unrestrictedly allows version 5 - since version 5 signatures are not yet available, ignore_invalid is set for this key.

signature.v3 = 2017-01-01
signature.v4 = 2030-01-01
signature.v5 = "always"
signature.ignore_invalid = "v5"

Complete list of sections and keys

[hash_algorithms]
md5 = ...
sha1 = ...
ripemd160 = ...
sha256 = ...
sha384 = ...
sha512 = ...
sha224 = ...

[asymmetric_algorithms]
rsa1024 = ...
rsa2048 = ...
rsa3072 = ...
rsa4096 = ...
elgamal1024 = ...
elgamal2048 = ...
elgamal3072 = ...
elgamal4096 = ...
dsa1024 = ...
dsa2048 = ...
dsa3072 = ...
dsa4096 = ...
nistp256 = ...
nistp384 = ...
nistp521 = ...
brainpoolp256 = ...
brainpoolp512 = ...
cv25519 = ...

[symmetric_algorithms]
idea = ...
tripledes = ...
cast5 = ...
blowfish = ...
aes128 = ...
aes192 = ...
aes256 = ...
twofish = ...
camellia128 = ...
camellia192 = ...
camellia256 = ...

[aead_algorithms]
eax = ...
ocb = ...

[packets]
pkesk = ...
signature = ...
skesk = ...
onepasssig = ...
secretkey = ...
publickey = ...
secretsubkey = ...
compresseddata = ...
sed = ...
marker = ...
literal = ...
trust = ...
userid = ...
publicsubkey = ...
userattribute = ...
seip = ...
mdc = ...
aed = ...

Files

TODO: https://gitlab.com/sequoia-pgp/sequoia-sq/-/issues/299

Intended content:

  • Which files/directories are used/created by sq, what is their purpose
  • Backing up and restoring a "known good state"
  • Switching between "states"
    • ENV-Variables

Directories

Sequoia PGP (and therefore sq) stores it's state - mainly keys and certificates - in a directory structure. The default locations are:

  • The certificate store (short cert store): $HOME/.local/share/pgp.cert.d
  • The key store: $HOME/.local/share/sequoia/keystore
  • The revocation certificate store: $HOME/.local/share/sequoia/revocation-certificates

These default locations can be changed by setting the environment variable SEQUOIA_HOME. There are subtle changes in the directory structure when using SEQUOIA_HOME:

  • The certificate store is: $SEQUOIA_HOME/data/pgp.cert.d
  • The key store is: $SEQUOIA_HOME/data/keystore
  • The revocation certificate store is: $SEQUOIA_HOME/data/revocation-certificates

If $SEQUOIA_HOME equals $HOME, then the default directory structure applies, as if SEQUOIA_HOME is not set.

The location of the cert store can be overridden by setting PGP_CERT_D or SQ_CERT_STORE. SQ_CERT_STORE has precedence over PGP_CERT_D. Both override the implied setting from SEQUOIA_HOME.

The location of the key store can be overridden by setting SQ_KEY_STORE, there is no second environment variable in this case.

All these locations can also be specified on the command line, which will override the environment variables.

Keystore

The keystore contains keypairs, public and secret key material, together with user ids and further metadata bundled together in files. These files are located in the subdirectory softkeys - 'hard keys' are keys stored on specialized hardware like smart cards.

The keystore corresponds to the secret keyring known from GnuPG.

Certificate store

The certificate store contains all certificates imported via sq cert import or fetched by sq network search. It also contains the keys for the intermediate CAs, the local trust root and a SQLite database for cert lookup.

The certificate store corresponds (roughly) to the public keyring known from GnuPG.

Revocation certificate store

Revocation certificates are created when keys are created. When a key is generated in the keystore, its revocation certificate gets stored in the revocation certificate store.

This revocation certificate is unspecific on the reason for revocation (which equals to 'compromised'). It's meant as a last resort, if the original key is lost and a more specific revocation cannot be created.

Upgrading a certification signature from SHA1 to SHA256

A certification signature is a way to store the assertion that a binding between a User ID (like an email address) and a public key is authentic. The certification signature is added to the certificate containing the binding. This augmented certificate can then be published, allowing other users to see and consider this assertion.

The first certification signature is added to a key when it's generated. It selfsigns the key creating a binding between it's public key and it's initial User IDs. Revocation certificates also contain a certification signature for verifying the authenticity of the revocation.

The certification signature is created by hashing the public key and the User ID, and subsequently signing the resulting hash value. Ideally the hash value for the combination of public key and User ID should be unique. Hash values however are of limited size which implies an information loss – there exist other input values, which produce the same hash value. The consequence of these collisions is that a certification signature asserts authenticity of an unlimited amount of public key - User ID pairs. Obviously this is not intended.

One design criteria for a hash function used for the creation of certification signatures is that these collisions are next to impossible to construct making the abuse of a collision infeasible in practice.

SHA1 is one of such hash functions. Over the time careful research concluded that SHA1 was less robust against collision construction than initially thought. Combined with the expanding availability of computing power SHA1 became vulnerable, meaning the construction of a fitting public key – User ID pair for a hash value became a realistic scenario. The remedy is to replace a SHA1 hash with a hash calculated by a stronger hash function: SHA256.

Check for SHA1 signatures in certificates

We use sq cert lint to check for certificates that use SHA1 signatures. sq cert lint takes the certificate(s) to examine either a a file parameter or from stdin.

This example takes the certificates from gpg using a keyring which contains just two vulnerable keys.

$ gpg --export | sq cert lint
Certificate 27E8C659C86F1C42 is not valid under the standard policy: No binding signature at time 2024-04-18T09:26:21Z
Certificate 27E8C659C86F1C42 contains a User ID ("Bob Example (GnuPG 1.4.18 Testkey) <bob@example.com>") protected by SHA-1
Certificate 27E8C659C86F1C42, key 739247043F705BAD uses a SHA-1-protected binding signature.
Certificate 9C2437DF50A1F904 is not valid under the standard policy: No binding signature at time 2024-04-18T09:26:21Z
Certificate 9C2437DF50A1F904 contains a User ID ("Alice Example (GnuPG 1.4.18 Testkey) <alice@example.com>") protected by SHA-1
Certificate 9C2437DF50A1F904, key 6FBFA7A845431489 uses a SHA-1-protected binding signature.
Examined 4 certificates.
  0 certificates are invalid and were not linted. (GOOD)
  4 certificates were linted.
  2 of the 4 certificates (50%) have at least one issue. (BAD)
0 of the linted certificates were revoked.
  0 of the 0 certificates has revocation certificates that are weaker than the certificate and should be recreated. (GOOD)
0 of the linted certificates were expired.
4 of the non-revoked linted certificates have at least one non-revoked User ID:
  2 have at least one User ID protected by SHA-1. (BAD)
  2 have all User IDs protected by SHA-1. (BAD)
4 of the non-revoked linted certificates have at least one non-revoked, live subkey:
  2 have at least one non-revoked, live subkey with a binding signature that uses SHA-1. (BAD)
0 of the non-revoked linted certificates have at least one non-revoked, live, signing-capable subkey:
  0 certificates have at least one non-revoked, live, signing-capable subkey with a strong binding signature, but a backsig that uses SHA-1. (GOOD)

Adding --list-keys gives a shorter output, containing only the fingerprints of certificates with issues.

$ gpg --export | sq cert lint --list-keys
F39D47AD38E2FC90D86FB94B27E8C659C86F1C42
000D6166AEC5E2EDA801BC259C2437DF50A1F904
Examined 4 certificates.

Adding User IDs allows to constrain the certificates considered.

$ gpg --export bob@example.com | sq cert lint
Certificate 27E8C659C86F1C42 is not valid under the standard policy: No binding signature at time 2024-04-17T12:10:44Z
Certificate 27E8C659C86F1C42 contains a User ID ("Bob Example (GnuPG 1.4.18 Testkey) <bob@example.com>") protected by SHA-1
Certificate 27E8C659C86F1C42, key 739247043F705BAD uses a SHA-1-protected binding signature.
Examined 1 certificate.
  0 certificates are invalid and were not linted. (GOOD)
  1 certificate was linted.
  1 of the 1 certificates (100%) has at least one issue. (BAD)
0 of the linted certificates were revoked.
  0 of the 0 certificates has revocation certificates that are weaker than the certificate and should be recreated. (GOOD)
0 of the linted certificates were expired.
1 of the non-revoked linted certificate has at least one non-revoked User ID:
  1 has at least one User ID protected by SHA-1. (BAD)
  1 has all User IDs protected by SHA-1. (BAD)
1 of the non-revoked linted certificates has at least one non-revoked, live subkey:
  1 has at least one non-revoked, live subkey with a binding signature that uses SHA-1. (BAD)
0 of the non-revoked linted certificates have at least one non-revoked, live, signing-capable subkey:
  0 certificates have at least one non-revoked, live, signing-capable subkey with a strong binding signature, but a backsig that uses SHA-1. (GOOD)

To fix a certification signature a secret key is needed.

Exporting a "secret key" actually exports the keypair - the secret key material and the public certificate.

Passing --fix to sq cert lint causes sq to generate new certifications using SHA256 as hash function. The result is written to stdout and can be passed to gpg for import.

  $ gpg --export-secret-key bob@example.com | sq cert lint --fix | gpg --import
Certificate 27E8C659C86F1C42 is not valid under the standard policy: No binding signature at time 2024-04-17T12:20:50Z
Certificate 27E8C659C86F1C42 contains a User ID ("Bob Example (GnuPG 1.4.18 Testkey) <bob@example.com>") protected by SHA-1
Certificate 27E8C659C86F1C42, key 739247043F705BAD uses a SHA-1-protected binding signature.
Examined 1 certificate.
  0 certificates are invalid and were not linted. (GOOD)
  1 certificate was linted.
  1 of the 1 certificates (100%) has at least one issue. (BAD)
0 of the linted certificates were revoked.
  0 of the 0 certificates has revocation certificates that are weaker than the certificate and should be recreated. (GOOD)
0 of the linted certificates were expired.
1 of the non-revoked linted certificate has at least one non-revoked User ID:
  1 has at least one User ID protected by SHA-1. (BAD)
  1 has all User IDs protected by SHA-1. (BAD)
1 of the non-revoked linted certificates has at least one non-revoked, live subkey:
  1 has at least one non-revoked, live subkey with a binding signature that uses SHA-1. (BAD)
0 of the non-revoked linted certificates have at least one non-revoked, live, signing-capable subkey:
  0 certificates have at least one non-revoked, live, signing-capable subkey with a strong binding signature, but a backsig that uses SHA-1. (GOOD)
gpg: key 27E8C659C86F1C42: "Bob Example (GnuPG 1.4.18 Testkey) <bob@example.com>" 2 new signatures
gpg: Total number processed: 1
gpg:         new signatures: 2

The output looks similar to the output above. We now have a look at the cert again, expecting it to be linted:

$ gpg --export bob@example.com | sq cert lint

sq cert lint produces no output if no certification with issues is found.

For a closer look sq toolbox packet dump can be used.

$ gpg --export bob@example.com | sq toolbox packet dump
Public-Key Packet, old CTB, 269 bytes
    Version: 4
    Creation time: 2024-04-17 09:46:37 UTC
    Pk algo: RSA
    Pk size: 2048 bits
    Fingerprint: F39D47AD38E2FC90D86FB94B27E8C659C86F1C42
    KeyID: 27E8C659C86F1C42
  
User ID Packet, old CTB, 52 bytes
    Value: Bob Example (GnuPG 1.4.18 Testkey) <bob@example.com>
  
Signature Packet, old CTB, 318 bytes
    Version: 4
    Type: PositiveCertification
    Pk algo: RSA
    Hash algo: SHA1
    Hashed area:
      Signature creation time: 2024-04-17 09:46:37 UTC
      Key flags: CS
      Key expiration time: 11months 30days 3h 50m 24s
      Symmetric algo preferences: AES256, AES192, AES128, CAST5, TripleDES
      Hash preferences: SHA256, SHA1, SHA384, SHA512, SHA224
      Compression preferences: Zlib, BZip2, Zip
      Features: SEIPDv1
      Keyserver preferences: no modify
    Unhashed area:
      Issuer: 27E8C659C86F1C42
    Digest prefix: 23A9
    Level: 0 (signature over data)
  
Signature Packet, old CTB, 408 bytes
    Version: 4
    Type: PositiveCertification
    Pk algo: RSA
    Hash algo: SHA256
    Hashed area:
      Signature creation time: 2024-04-17 12:20:50 UTC (critical)
      Key expiration time: 11months 30days 3h 50m 24s
      Symmetric algo preferences: AES256, AES192, AES128
      Issuer: 27E8C659C86F1C42
      Notation: salt@notations.sequoia-pgp.org
        00000000  81 e7 68 6d aa e8 67 8e  68 f9 15 96 fa 79 f1 2a
        00000010  51 54 e4 9a b8 2a 82 4d  0d 47 88 72 e9 44 45 12
      Hash preferences: SHA256, SHA512
      Compression preferences: Zlib, BZip2, Zip
      Keyserver preferences: no modify
      Key flags: CS
      Features: SEIPDv1
      Issuer Fingerprint: F39D47AD38E2FC90D86FB94B27E8C659C86F1C42
    Digest prefix: 9A8C
    Level: 0 (signature over data)
  
Public-Subkey Packet, old CTB, 269 bytes
    Version: 4
    Creation time: 2024-04-17 09:46:37 UTC
    Pk algo: RSA
    Pk size: 2048 bits
    Fingerprint: 509105DD8BB39C3925F939BE739247043F705BAD
    KeyID: 739247043F705BAD
  
Signature Packet, old CTB, 293 bytes
    Version: 4
    Type: SubkeyBinding
    Pk algo: RSA
    Hash algo: SHA1
    Hashed area:
      Signature creation time: 2024-04-17 09:46:37 UTC
      Key flags: EtEr
      Key expiration time: 11months 30days 3h 50m 24s
    Unhashed area:
      Issuer: 27E8C659C86F1C42
    Digest prefix: 882A
    Level: 0 (signature over data)
  
Signature Packet, old CTB, 388 bytes
    Version: 4
    Type: SubkeyBinding
    Pk algo: RSA
    Hash algo: SHA256
    Hashed area:
      Signature creation time: 2024-04-17 12:20:50 UTC (critical)
      Key expiration time: 11months 30days 3h 50m 24s
      Issuer: 27E8C659C86F1C42
      Notation: salt@notations.sequoia-pgp.org
        00000000  b1 73 8c 9b 5c f2 0b d9  69 d7 cb 67 46 b1 ef bb
        00000010  c4 1c 88 23 98 36 06 50  a9 5d ca 35 26 b5 b8 a7
      Key flags: EtEr
      Issuer Fingerprint: F39D47AD38E2FC90D86FB94B27E8C659C86F1C42
    Digest prefix: 5381
    Level: 0 (signature over data)

Note that the old SHA1 certifications are still within the certificate.

Fixing a revocation certificate

First, lets look into a revocation certificate to examine the hash algorithm used. In this example bob.pgp.rev contains the revocation certificate. Use sq toolbox packet dump to have a closer look.

$ sq toolbox packet dump bob.pgp.rev
Signature Packet, old CTB, 302 bytes
    Version: 4
    Type: KeyRevocation
    Pk algo: RSA
    Hash algo: SHA1
    Hashed area:
      Signature creation time: 2024-04-18 09:48:29 UTC
      Reason for revocation: Key is retired and no longer used, Test revocation
    Unhashed area:
      Issuer: 27E8C659C86F1C42
    Digest prefix: 18DB
    Level: 0 (signature over data)

Hash algo tells the used algorithm, SHA1 in this case.

sq cert lint is not meant to fix this issue. Instead simply create a new revocation certificate.

Note: The generation of a revocation certificate only works with keys containing SHA256 certifications. See above how fix keys in case they are missing.

$ gpg --export-secret-key bob@example.com | sq key userid revoke "Bob Example (GnuPG 1.4.18 Testkey) <bob@example.com>" 'retired' 'Test revocation with sq' > bob.pgp.rev
$ sq inspect bob_new.pgp.rev
-: Revocation Certificate.

    Fingerprint: F39D47AD38E2FC90D86FB94B27E8C659C86F1C42
                 Invalid: No binding signature at time 2024-05-06T11:50:46Z
Public-key algo: RSA
Public-key size: 2048 bits
  Creation time: 2024-04-17 09:46:37 UTC

         UserID: Bob Example (GnuPG 1.4.18 Testkey) <bob@example.com>
                 Revoked:
                  - User ID information is no longer valid
                    On: 2024-05-06 11:50:46 UTC
                    Message: "Test revocation with sq"
                 Invalid: No binding signature at time 2024-05-06T11:50:46Z

Inspect key, certificates, messages and the like

Sometimes you want a closer look on the objects sq works with, for instance if you want to troubleshoot a failing operation. sq offers two levels of details: inspect and the subcommand hierarchy under sq packet.

The workhorse of these two is sq inspect. It show a human readable extract of the object passed to it. The most general application is:

$ sq inspect FILE

FILE can be a certificate, a key, a message - it can be any file even a non-OpenPGP one:

$ sq inspect /etc/fstab 
/etc/fstab: No OpenPGP data.

The output of a certificate looks like this:

$ sq inspect bob.cert
bob.cert: OpenPGP Certificate.

      Fingerprint: 265BA2AB62FFF0B67AF62A70A9FE49218A6A88B0
  Public-key algo: EdDSA
  Public-key size: 256 bits
    Creation time: 2024-10-28 11:31:56 UTC
  Expiration time: 2027-10-29 04:58:17 UTC (creation time + 2years 11months 30days 9h 16m 45s)
        Key flags: certification

           Subkey: 8600DB2A7FB8BFE5DAAA922884B61A3ABEACD605
  Public-key algo: EdDSA
  Public-key size: 256 bits
    Creation time: 2024-10-28 11:31:56 UTC
  Expiration time: 2027-10-29 04:58:17 UTC (creation time + 2years 11months 30days 9h 16m 45s)
        Key flags: authentication

           Subkey: 60F64238FDD763AFF76677928A880E8E21CC6C3E
  Public-key algo: EdDSA
  Public-key size: 256 bits
    Creation time: 2024-10-28 11:31:56 UTC
  Expiration time: 2027-10-29 04:58:17 UTC (creation time + 2years 11months 30days 9h 16m 45s)
        Key flags: signing

           Subkey: 41E5C9C3AC983EA9CC04649A9754F1AB759E21AF
  Public-key algo: ECDH
  Public-key size: 256 bits
    Creation time: 2024-10-28 11:31:56 UTC
  Expiration time: 2027-10-29 04:58:17 UTC (creation time + 2years 11months 30days 9h 16m 45s)
        Key flags: transport encryption, data-at-rest encryption

           UserID: <bob@example.com>
   Certifications: 1, use --certifications to list

           UserID: Bob

If FILE is omitted sq inspect reads from STDIN.

$ echo "hello" | sq encrypt --for-email alice@example.com | sq inspect
-: Encrypted OpenPGP Message.

      Recipient: 70481B0CCFC64D03

In this example, we create an encrypted message on the fly. The message in clear ("hello") is passed through sq encrypt and then forwarded to sq inspect.

A revocation certificate looks like:

$ sq inspect bob.rev
bob.rev: Revocation Certificate.

      Fingerprint: 7C4A15AD3C51181E43B534DE120862007D362AF2
                   Revoked:
                    - No reason specified
                      On: 2024-10-28 11:36:16 UTC
                      Message: Unspecified
                   Invalid: No binding signature at time 2024-10-28T13:25:00Z
  Public-key algo: EdDSA
  Public-key size: 256 bits
    Creation time: 2024-10-28 11:36:16 UTC

You can experiment with sq inspect - as it only reads data, it will not cause any damage.

Data from within the certificate store is also accessible:

$ sq inspect --cert 7C4A15AD3C51181E43B534DE120862007D362AF2
OpenPGP Certificate.
[...]

When inspecting certificates, certifications of this certificate are hidden. You can display certifications by passing --certifications to sq inspect.

$ sq inspect --cert 7C4A15AD3C51181E43B534DE120862007D362AF2 --certifications
OpenPGP Certificate.

      Fingerprint: 7C4A15AD3C51181E43B534DE120862007D362AF2
  Public-key algo: EdDSA
  Public-key size: 256 bits
    Creation time: 2024-10-28 11:36:16 UTC
  Expiration time: 2027-10-29 05:02:37 UTC (creation time + 2years 11months 30days 9h 16m 45s)
        Key flags: certification

           Subkey: F753DAA5EE1633D6B6B7071F4ED3187E3CE8EC04
  Public-key algo: EdDSA
  Public-key size: 256 bits
    Creation time: 2024-10-28 11:36:16 UTC
  Expiration time: 2027-10-29 05:02:37 UTC (creation time + 2years 11months 30days 9h 16m 45s)
        Key flags: signing

           Subkey: DF676EC1ADA16D84DF6B197881FE2BA966469B1E
  Public-key algo: EdDSA
  Public-key size: 256 bits
    Creation time: 2024-10-28 11:36:16 UTC
  Expiration time: 2027-10-29 05:02:37 UTC (creation time + 2years 11months 30days 9h 16m 45s)
        Key flags: authentication

           Subkey: 3B5DE910F20C2D9A4989D15E90E3343A16CA864D
  Public-key algo: ECDH
  Public-key size: 256 bits
    Creation time: 2024-10-28 11:36:16 UTC
  Expiration time: 2027-10-29 05:02:37 UTC (creation time + 2years 11months 30days 9h 16m 45s)
        Key flags: transport encryption, data-at-rest encryption

           UserID: <bob@example.com>
    Certification: Creation time: 2024-10-28 11:38:35 UTC
                   Expiration time: 2029-10-28 16:42:30 UTC (after 5 years)
                   Trust depth: 1
                   Trust amount: 120
                   Regular expression: "<[^>]+[@.]example\\.com>$"
                   Alleged certifier: 188C014A41FD5FF4D83A35A0A879D7033A9B6293
                       <alice@example.com> (authenticated)
                   Hash algorithm: SHA512
    Certification: Creation time: 2024-10-28 11:36:25 UTC
                   Trust depth: 255
                   Trust amount: 120
                   Alleged certifier: B9C899C70BE20C10D794E924288ADA34F36309B1
                       Local Trust Root (authenticated)
                   Hash algorithm: SHA512
             Note: Certifications have NOT been verified!

Packet dump

There is a even deeper dive possible. You can list the packets an OpenPGP artifact (message, certificate, signature, etc) is comprised of.

In this example, we generate an encrypted message and display it's packet structure:

$ echo "hello" | sq encrypt --for-email bob@example.com | sq packet dump
Public-Key Encrypted Session Key Packet, new CTB, 94 bytes
    Version: 3
    Recipient: 90E3343A16CA864D
    Pk algo: ECDH
  
Public-Key Encrypted Session Key Packet, new CTB, 94 bytes
    Version: 3
    Recipient: 90E3343A16CA864D
    Pk algo: ECDH
  
Sym. Encrypted and Integrity Protected Data Packet, new CTB, 55 bytes
│   Version: 1
│   Session key: E2A9BB6A3A94127C240346792AE53806A722B45BCB8DEB1A249F8E43405F5D9C
│   Symmetric algo: AES-256
│   Decryption successful
│ 
├── Literal Data Packet, new CTB, 12 bytes
│       Format: Binary data
│       Content: "hello\n"
│     
└── Modification Detection Code Packet, new CTB, 20 bytes
        Digest: EA9382CBE41EB2A2F1B40E9E6C3529873B67FE8F
        Computed digest: EA9382CBE41EB2A2F1B40E9E6C3529873B67FE8F

The output of sq packet dump shows the wire format - the sequence and content of the different packets composing an OpenPGP artifact.

Objects from the certificate store are also available:

$ sq packet dump --cert 7C4A15AD3C51181E43B534DE120862007D362AF2

Like sq inspect sq packet dump only reads data, so it's save to experiment with it.

Background

This chapter discusses some of underlying concepts of OpenPGP and public key cryptography in general.

Characteristics of a secure system

A communication system has to provide certain guarantees to be called secure. While there are certainly a lot of characteristics which are wishful in a communication system, the requirements for a secure system can be summarized as confidentiality, integrity and authenticity. These three characteristics have to hold, if one of them is weak or even missing, the whole system cannot be considered secure.

Security has to be distinguished from clandestinity. A secure system is not required to hide the fact that communication is taking place or to obfuscate it's participants. That would constitute a different requirement on a communication system.

Also not included are mechanisms to contain the consequences of a breach. Perfect forward secrecy, future secrecy, plausible deniability are methods to limit the effect of a compromise - how much an attacker gains by knowing the encryption secret (the key) at some point in time. For a system to by called secure it's not required to implement them.

Although this definition of security might seem very limited and real world application will certainly also implement the other mentioned characteristics, it helps reasoning about a system if the definition is clear cut and doesn't include neighboring concerns.

Confidentiality

Confidentiality means that only the intended receivers of a message are able to read it. Everybody else should only see an undecipherable lump of seemingly random characters. This is where encryption algorithms are used. For an in depth discussion of encryption see the background text on public key cryptography (TODO: Link). Encryption traditionally cares about the content of a message. Sender, receiver, time of sending, size of the message - all the meta information about the communication itself is not addressed by encryption.

This ignores the fact that the mere communication between two users might allow an educated guess of the content.

Integrity

Integrity ensures that messages reach their intended receivers unmodified. Any modification done to a message while in transit should be immediately obvious.

This looks like it's already achieved by encryption, because a successful modification requires the knowledge of the encryption key. Without that key a modification would corrupt the message. If the message was a text, the damage would be obvious - if it was a binary, the damage might even represent valid content. Another attack would be to simply append an old, intercepted message to a new one. Depending on how the encryption works in detail, this might go unnoticed since the encryption key would be the right one.

To decouple the guaranty of integrity from the applied encryption - the guaranty of confidentiality - actual systems use checksums of the content to detect modifications.

Authenticity

Authenticity is about the certainty that a message actually comes from it's alleged sender. Impersonation should be impossible or obvious if it's attempted. More generally authenticity protects against a man-in-the-middle attack. Or spelled the other way around: Man-in-the-middle attacks are basically attempts to subvert the methods of guarantying authenticity within a communication system.

This is usually realized by adding a piece of data to the communication which only the alleged sender can create, but everyone else can validate.

Open source and reproducability

While open source and reproducability are not part of the requirements for a secure system, for all practical purposes it's better to be able to validate the promises of a software vendor than be forced to blindly believe them.

Being open source of course doesn't imply that a validation (aka code audit) has taken place, that the software uphold it's promises and is free of bugs. In contrast to closed source software (which shares the same problems), there is at least the possibility.

Keys, subkeys and certificates

A key in the context of OpenPGP is actually a dataset containing User IDs, key material (both public and secret), metadata like the expiration date, preferences, certifications, lots of signatures and subkeys - to name a few. This dataset is not fixed, parts of it will (likely) be modified over time as new certifications might be added, User IDs might change and the expiration might be prolonged.

A key is needed for operations only the keyholder should be able to do, like decrypting or signing.

A certificate is the public representation of a key. It contains the same objects as the key with the exception of the secret key material. It is used for operations everyone should be able to do, like encryption or signature verification.

The objects within a key (and a certificate) can be signed using the secret key material of that key. This signifies that the keyholder either added the object herself or is content with it (like third party certifications). Keys and specifically certificates can also hold unsigned objects like additional User IDs or unapproved certifications.

Keys (and certificates) can and usually have subkeys. These are keys which are bound to another key (called primary key) by a subkey binding signature.

Subkeys introduce new key material to keys. With subkeys, a key can have different key material for different operations, thus avoids using the same material for (say) signing and encrypting. As certifications are always for the primary key, key rotation or revocation of subkeys doesn't effect them. That way updating your key material (or switching the cipher) doesn't impact the web of trust.

Subkeys do not have User IDs, these are associated with the primary key, but they (can) have an expiration date. They are also marked for an intended use case.

There is no limit to the number of subkeys a key can have. When generating a new key, sq creates 3 subkeys with it. One for encryption, one for signing and one for authentication. The primary key is used to certify the authenticity of the subkeys. As subkeys have markings (flags) for their use case, an application (like sq) can choose the right subkey for each operation. In some ways a key is a little PKI with the primary key acting as a certificate authority, certifying the subkeys.

You can have a peek into a key by:

$ sq key generate --own-key --userid alice --output - --rev-cert /dev/null --overwrite | sq packet dump

This example generates a key with a User ID of "alice", it specifies --output, so that the generated key is not added to the key store. Using --output - redirects the new key to STDOUT, so that sq packet dump can display it's contents. --rev-cert and --overwrite are needed as a side effect of --output - in this example the result is discarded. --own-key authorizes the new key to introduce certificates - you can try --shared-key instead to see an unauthorized key.

Public key cryptography

Encryption

Every now and then, you might want to have a private word with someone. Private in the sense that you can control who is following the conversation, excluding unwanted listeners, but not necessary hiding that the a conversation is taking place. Technically speaking, this setting composes a secure channel. If you don't have control or cannot even estimate the number of people which can follow a conversation, this conversation uses an insecure channel.

People learn early in life how the establish a secure channel - for instance by whispering or changing the location. Both methods however are difficult to achieve in the internet. Apart from edge cases, the internet consists only of insecure channels - security was no design criteria, when the internet was first conceptualized. A secure channel over the internet has to be build on top of insecure channel(s). This can be done by using a "language", which can only be understood by the intended participants. This - in its broadest sense - is encryption.

Technically it's not exactly a new language which is used, but a new notation. The usual schemes contain methods like changing the alphabet and reordering the sequence of characters. Concrete schemes use an algorithm and a secret key to specify this notation. The algorithm itself is not secret. Certainly, keeping the algorithm secret makes an attack harder, but comes with drawbacks. Current algorithms are thoroughly scrutinized, so that their publication does not help an attacker.

Probably the biggest advantage with publicly available algorithms is that it can be reused for different secure channels, as its protective character lies completely within the secret key. Choosing a new secret gives you a new channel without sacrificing the protection of either the new channel or already existing ones.

Symmetric encryption

Symmetric encryption uses the same secret key for encryption and decryption, decryption is simply done by repeating the steps of the encryption, but in reverse order - undoing what encryption did to the original text. The constrictions for designing an algorithm for symmetric encryption are usually not imposed by capabilities of CPUs, which means that contemporary algorithms are optimized for performance - symmetric encryption is fast.

Symmetric encryption however is not well suited for establishing a secure channel. This is not due to weak algorithms, but merely the fact that sender and receiver have to have the same secret key - and nobody else. This implies that for the exchange of that key a secure channel is needed - a hen and egg problem.

Symmetric encryption is used, where either a secret does not need to be shared (hard disk encryption, for instance), or where other effective ways exist for the exchange.

Asymmetric encryption

Asymmetric encryption solves the key distribution problem. Its design criteria however are radically different from symmetric encryption.

Asymmetric encryption uses mathematical functions, where the inverse of that function is infeasible to calculate in any meaningful time frame. As an example: it's easy to multiply to prime numbers, but it's hard to reverse this operation, finding the prime factors, if you only have the resulting number. Thus decryption cannot be achieved as it would be with symmetric encryption - reversing the encryption steps would be to costly, even if you know the key.

Instead asymmetric encryption uses functions which allow for a trapdoor, a way to calculate the inverse of that function by different means. This is done by not reversing encryption, but by encrypting a second time - with a different key. Obviously there has to be a mathematical relationship between the key used for encryption and the one used for decryption. In fact, keys for asymmetric encryption are constructed as pairs. And: they are interchangeable - no matter which key you used for encryption, you need the other one of the pair to decrypt.

For a complete cycle - clear text -> encrypted text -> clear text - both keys are necessary. Knowing only one of them is not enough, so it doesn't compromise the security of this mechanism if one of them is publicly known. This is probably the most difficult part of asymmetric encryption to understand and rely on.

Given that one key of the pair is publicly known, it can be used for the clear text -> encrypted text step. Anyone how is in possession of the other key of the pair can complete the cycle: encrypted text -> clear text. So you better keep that key private.

In OpenPGP, the pair (both keys) is included in the "key", whereas the public part of the pair goes into the "certificate". The certificate can (and should) then be disseminated.

Hybrid encryption

OpenPGP uses both, symmetric and asymmetric encryption. It combines the speed of symmetric encryption, using the key distribution capabilities of asymmetric encryption.

A message is first symmetrically encrypted using a random, unique key, which then is asymmetrically encrypted for each receiver of the message and added to it. A receiver has to asymmetrically decrypt the right key and use it to symmetrically decrypt the message. Besides speed, this scheme has the advantage, that each additional receiver only adds little to the resulting size of the encrypted message.

Signatures

Signatures are used to signify authenticity. The alleged creator of a message adds something to that message which only she can create, but everyone else can verify. This is done by encrypting the checksum of the message with the private part of the key pair. Since the public part of the pair is - well - public, anyone can decrypt that checksum and see if it is indeed the checksum of the message. Assuming the private key to really be private, this is a proof of authenticity.

User IDs

OpenPGP knows User IDs - they are the human readable content of certificates (and keys) and are meant as representations of the keyholder, for instance in form of an email address. Technically, User IDs are just sequences of printable characters. Their content depends on the intended use case. To retrieve a certificate for a certain email address, the certificate contains a User ID having the said email address.

<alice@example.com>

User IDs are not limited to email addresses, they can consist of a name

Alice Example

or a combination of both

Alice Example <alice@example.com>

As email addresses have to be in angle brackets, they are identifiable. Other use cases may have different conventions.

sq allows a shortcut. Instead of specifying an email User ID as --userid "<alice@example.com>" you can use --email "alice@example.com". sq takes care of the angle brackets.

In Public Key Cryptography User IDs are not needed. Encryption, decryption, signing and verification are not using the information supplied in a User ID. User IDs are meant as markers to allow for a key retrieval or identification without having to resort to fingerprints. As such they are included in keys and certificates - their untaintedness is ensured by signatures also contained in the key or certificate. There is no limit in the number of User IDs a key or certificate can contain.

User IDs can be added to a key at any time, they don't have to be all present at the time of a keys generation.

User IDs are claims - anyone can create a key containing <alice@example.com> as a User ID and publish it's certificate. How to validate the authenticity - the soundness of the claim - is described in chapter Authenticating certificates.

Removing a User ID from a key is complex. While it's technically possible to strip a User ID from a key, once the corresponding certificate got disseminated it's impossible to call that back. Then a User ID has to be revoked, it will stay in the key with a revocation certificate added. The revocation will also be part of certificates generated from that key, giving the software processing these certificates a hint on how to handle that User ID (such as ignoring it).

Web of Trust

There are relationships between keys, certificates, signatures etc., which are computable. Given a file, a detached signature and a certificate, one can calculate if the signature is made over the file using the key corresponding to the certificate. There is no other (outside) information, no context needed to validate this relationship.

Cryptographic keys and certificates are rarely (if at all) used without context. A context which comes to mind would be email encryption. This context introduces a new set of entities, namely email addresses. There is no way to derive the key from the email address alone - there is no computable relationship. For that a mapping is needed, which binds an email address to a key (and vice versa).

By definition this mapping is arbitrary and not computable - otherwise it wouldn't be needed. Technically any email address can bind to any key. In that sense a binding is no more than a claim.

This introduces the problem of authenticity: Is the claimed binding correct, is the holder of the key also owner of that email address? As this problem cannot be computably solved, it has to be addressed by other means: Human intervention - also known as "work".

Authenticity can only be established by humans.

This is not a good requirement, since humans tend to avoid work. This leads to keys being used without proper authentication, signatures not being checked and so on.

If human work cannot be eliminated from that process, it makes sense to use the result of that work in the most efficient way.

Probably the first optimization of this process which comes to mind is the avoidance of repeating work. For this the results of work (of authenticating a binding) has to be captured in a persistent form which can be stored and reused. OpenPGP realizes this by creating a signature, where the person doing the work signs the authenticated binding. Next time a key lookup is done, the signature will be recognized and the binding will be taken as authentic - which is a process that happens without human intervention.

The signature as a result of work can be seen as a product. This product can be passed on to others, so that they too can benefit from the work inside it.

This approach is not limited to OpenPGP, x509 operates along the same idea where some authority attests authenticity and spreads this attestation.

This gives rise to a new problem: Product quality. The signature gives no clue on how diligent the authentication was performed, if at all.

There is no good solution to this problem. Unless repeating the authentication and comparing the result, one can only rely on the reputation of the individual (or institution) which made the attestation. OpenPGP supports this reputation model by formalizing a way to attest good reputation - good work. This is done by assigning a trust depth while certifying the authenticity of a certificate / User ID binding. A trust depth of one for instance means that the attestation of authenticity not only covers the actual binding, but also attestations made by the certificate of that binding - the attestation spreads out one "hop". Higher levels of trust depth simply increase the number of hops an attestation covers.

Accompanying the outreach of a reputation, there is also the possibility to quantify it. Instead of attesting only a good reputation (or not), OpenPGP allows to assign a value between 0 and 120, expressing the trust in an attestation made by a certain keyholder. Such an attestation would then be viewed as "partially authenticated". The values can add up, if independent sources only express limited trust in a reputation, so that the result might qualify as "good enough" (for a certain use case).

So far a reputation can be characterized by it's outreach and it's (assumed) quality - the diligence put into the product. This can be further tuned by limiting the attestations to a certain range of user ids. That way only the attestations matching a supplied regular expression would be considered. A typical use case would be a certification authority of an institution, where only the attestations for user ids from that institution (having a specific mail domain) would benefit from the assigned outreach and trust amount. This doesn't stop a CA from attesting other user ids, but those attestations would be ignored.

Attestations are bundled with the corresponding certificates and can be circulated the same way the original certificate circulated. The way a certificate circulates might give hints on it's authenticity. This is usually done by using a communication channel which involves control over a certain resource linked to the User ID part of a binding. Using DANE for instance implies control over the DNS zone file of the mail domain. WKD implies control over a webserver answering on a domain linked to the mail domain. Other proofs of control might also give clues on the authenticity of a binding.

TODO: TOFU: Turning refusal of work into a feature. TOFU as a special "proof of control" as proof of stability

So far this situation is not yet a web of trust - it's more a soup of partially entangled certificates. In some sense this soup is result of the collective work of OpenPGP users, it's kind of a commons.

It gives you a glimpse on how others judge the authenticity of bindings, which certificates belong to a person with good reputation and so on. But these are judgments of other people. To benefit from the work contained in this soup one has to start using the products. This is done by attesting authenticity and trust depth to certificates from this soup - obviously not arbitrarily, but after checking. These certificates become personal trust anchors (or introducers) and are the starting point of a web of trust.

A web of trust is the result of personal choice thus differs between different users. This is in stark contrast to x509 where the trust anchors are defined by institutions - web browser vendors of instance.

Certificate Authorities

Imagine a NGO which wants to attest that the certificates of it's staff members are authentic - that they indeed work for this NGO and that the User IDs of these certificates are the right ones, are actual representations of staff members. In other words: The NGO wants to establish an authority which can be queried about the validity of a certificate.

While there are many ways to do so, the attestations should be processable by an algorithm - human involvement should not be necessary. Additionally the authority shouldn't be localized to avoid a single point of failure. A server in the internet which judges uploaded certificates is therefore not a solution for this recommendation.

A solution would be to create an additional key which sole purpose is to certify the staff members certificates by adding it's signature to them. An interested user could then search for this signature in a certificate to verify it's validity.

However given that anyone can create a key with the same User ID as the special signing key above and then sign certificates with it, the problem just got shifted. Instead of authenticating a staffs members certificate, you have to verify the signing keys authenticity. This introduces a beneficial indirection - members to the staff can leave, new ones can enter - as the signing key stays the same no further authentications are necessary for an outside user.

The signing key plays the role of a Certificate Authority.

Viewed from the outside such a setting of a CA key and signed certificates is just a bundle of entangled certificates. This bundle becomes useful when the CA key (or more precise: it's certificate) is used as a trust introducer.

limit/restrict the trust introducer. Should that be here, or in an other chapter?

Everyone can create a CA, it's not limited to established institutions. But usually the term CA denotes some degree of institutionalisation.

The certificate of a CA can itself be certified by other keys - either by (other) CAs or individuals.

And that's it: A Certificate Authority is just a key like any other, but used in a specific way.

Shadow CAs

The certificate of a CA key has to be publicly available to serve it's role.

The principle of delegation, the reliance on the authenticity of a binding to a designated key, can be used locally too. This is what Sequoia PGP (and therefore sq) does.

When first invoked sq creates a Local Trust Root, that is a key located in the local cert store which certifies other certificates.

A certificate is considered authenticated, if there is a path from the Local Trust Root to this certificate with a trust amount of 100% (or 120 out of 120).

sq further creates more (intermediate) CAs on demand. Their role is a record the provenience of a certificate and a trust amount derived from that provenience.

As an example: If you fetch the certificate of alice@example.com from the keyserver keys.openpgp.org, sq will create 2 internal CAs. One named Public Directories and one named Downloaded from keys.openpgp.org. It will then create a path Local Trust Root -> Public Directories -> Downloaded from keys.openpgp.org -> alice@example.com.

Along that path a trust amount is calculated: The internal CA Public Directories for instance is certified with a trust amount of 40/120. This amount creates an upper limit for the whole path, other CAs in that path can further reduce that amount but cannot increase it. Downloaded from keys.openpgp.org is certified by Public Directories with a trust amount of 1/120. The complete path from Local Trust Root to alice@example.com has therefore a combined trust amount of 1/120.

To increase this value, you could change the certifications of the internal CAs by creating new ones - or (the recommended way) by creating a new path between Local Trust Root and alice@example.com by using sq pki link add - linking alice@example.com and Local Trust Root. See chapter (TODO: add link) for an indepth explanation.

Besides calculating a trust amount, the path also shows from where a certificate originates and when it was included in the cert store, as certifications have a creation date.

These internal CAs are called Shadow CAs.

Subkeys

Modern OpenPGP keys are actually a set of keys. This set contains a primary key and (usually) several subkeys. When generating a new key with sq key generate, sq will create 3 subkeys along with the primary key: Each of the subkeys are marked for their respective use (authentication, signing, encryption).

This set of subkeys is identified by it's primary key, so adding and removing them doesn't change the fingerprint. Certifications are made for the primary key as well - so modifying the subkeys doesn't affect them.

Subkeys are just like ordinary keys. What makes a key a subkey, is the existence of a subkey binding signature, which marks a specific key as subkey to a primary key.

Subkeys are different from primary key, as they do not contain user ids.

Primary keys and subkeys can be thought of as a tiny local personal PKIs, where the primary key is the CA, certifying the subkeys.

Scenarios

The reason for using different subkeys for different purposes is to separate the functionalities to achieve the greatest possible safety without restricting their usability. They can be treated and stored differently depending on their purpose and security needs.

Subkeys are key pairs, but associated with the primary key. For example, there is a difference between GnuPG and Sequoia PGP in how keys are structured by default when it is generated. GnuPG generates a signing and certification key as primary key and an encryption subkey in addition, whereas Sequoia PGP generates a primary key for certification and respectively subkeys for authentication, signing and encryption.

The primary key should be the most protected one and therefore stored offline where no one can have access to it. For this reasons the best practice would be not to publish the primary cert. Instead it makes sense only to publish certs of subkeys to avoid that other people use the cert of primary key. Again, this is not a security consideration, but if people use the primary certificate, it will become difficult to keep the primary key offline.

In this scenarios subkeys are the ones to use for frequent work. Then you just need to publish the certificates of the respective subkeys. It makes sense to rotate them more often by revoking them faster and let them expire earlier than the primary key. The primary key can be used to revoke a subkey if it's needed.

To prevent losing data if an encryption subkey gets lost, it's necessary to have a backup of it in a safe place.
In case of a signing key it is not as important or even not recommended to have a backup file. This is simply to minimize the risk of key theft by avoiding storing it in two different places. The functionality will not be limited, signatures made previously with that key still remain valid and for future signatures you can easily generate a new one using the primary key.

Just a site note, in some countries there is even more a need to separate keys for encryption and signing in terms of key disclosure laws. For example in the UK and in France it can be construed as a crime not to decrypt and/or hand out a decryption key to law enforcement agencies if recommended even without a court order. In this cases the rest of the key material should remain safe.

  • How to use subkeys, especially how to use them when the primary key is offlined. sq key subkey export...
  • https://openpgp.dev/book/certificates.html#component-keys
  • different subkeys for different devices

Key expiration

OpenPGP keys may include an expiration date. This date is included when a certificate of this key is generated. The expiration date within a certificate gives the software processing the cert a hint on how to handle it. Email clients for instance might reject using an expired certificate to encrypt a message. Signature verifying software might display a warning, but continue to function.

The expiration date is optional. It's possible to create (or update) keys, so that they never expire. The expiration date does not imply that the certificate becomes "insecure" after that date. It's just a method to enforce an update.

There are different reasons for and effects of setting an expiration date for certificates. To answer the question whether it is an improval of security to set an expiration date, we think about possible threadmodels someone could face. Starting with a certificate expiring, you can always extend the certificate validity as long as you have access to the key.

If you lose your key due to hardware loss or damage without there being an attack, and still have your revocation file stored at an other place, you can simply revoke the key and the certificate, and don't have to wait for the expiration. If you don't have a revocation file, you can at least let it expire by itself.

If someone steels your key, the person would be able to compromise the key. Only a revocation file would help to avert the damage here too since the expiration date could also be manipulated by the attacker.

It can make sense to set different expiration dates for subkeys with different purposes. In the case that only a specific subkeys gets lost or stolen the primary key will remain valid.

Another reason to set an expiration dates which is often mentioned is that it forces people to refresh their certificates stores or pubrings on a regular basis. In summary, one can say that more important than setting an expiration date is to store the revocation file separately from the key in another location. Nevertheless in some cases setting an expiration date could limit a possible damage.

Fast lanes

Here you will find various short how-to guides on important functions of sq. The detailed main text respectively tutorial is linked in each document.

How to generate a key

To generate a key with sq, enter the following command in your command line:

$ sq key generate --own-key --name alice --email alice@example.com 

To learn about the possibilities and options around generating a key see chapter 'Key generation'.

Additional subkeys

How to generate an additional subkey

To generate and add an additional subkey to an existing certificate, see the following command, which exemplarily specifies the capability of signing and opts out the password protection:

$ sq key subkey add --cert $FINGERPRINT --can-sign  --without-password  

How to bind an existing subkey to another certificate

$ sq key subkey bind --key $KEY_TO_BE_BINDED_FINGERPRINT --cert $FINGERPRINT
 

To learn about the capabilities and other specifications of adding a subkey see chapter 'Adding a subkey'.

How to import and export a key

Import a key into keystore

$ sq key import $KEYFILE

Export a key from the keystore into a file

$ sq key export --cert $FINGERPRINT > $KEYFILE

See chapter 'Import and export of a key' for more detailed information.

How to encrypt a file

To encrypt a file with a certificate, use sq encrypt as it is shown here:

$ sq encrypt --for-email alice@example.com message.txt

Encrypting a message and adding a signature works as follows:

sq encrypt --signer $FINGERPRINT --for-email alice@example.com

See the complete instructions here: Chapter 'Encrypt and decrypt files'.

How to decrypt a file

To decrypt a file use sq decrypt, providing the name of the encrypted file and implicitly using a key in the keystore:

$ sq decrypt message.pgp

See also: Chapter 'Encrypt and decrypt files'

How to sign a file or message

To sign a file with an inlined signature use the following command:

$ sq sign --signer $FINGERPRINT $FILE

To separate the signature from the file, make a detached signature as follows:

$ sq sign --signer $FINGERPRINT --signature-file $FILE

More information is available here: Chapter 'Sign files'

How to verify a file or detached signature

To verify a signed file or a detached signature, use 'sq verify' like this:

$ sq verify file.txt

and for detached signatures:

$ sq verify --signature-file file.sig file.txt

See the complete instructions here: Chapter ''.

How to publish a certificate to servers

Keyservers

To publish a certificate to the preconfigured list of keyservers, export it and use the 'sq network keyserver publish' subcommand as follows:

$ sq network keyserver publish $FINGERPRINT

WKD

To generate a file and the directory structure to a local location from where it can be uploaded to a webserver like WKD you can use the 'sq network wkd generate' subcommand. In this example /tmp/foo is the directory everything will be generated into, the information 'sequoia-pgp.org' excludes User IDs from certificates with other domain data from the key store 'certs.cert':

$ sq network wkd generate /tmp/foo sequoia-pgp.org certs.cert

DANE

To publish a certificate by DNS / DANE, create a TXT record:

$ sq network dane generate sequoia-pgp.org certs.cert

See chapter 'Keyservers' for more information about this topics.

How to retrieve a certificate

To retrieve a certificate from a keyserver, use the sq network search $PATTERN subcommand for example as follows:

$ sq network search alice@example.org

To get more information like customizing the list of keyservers etc., see chapter 'Search a certificate in the internet'

How to revoke a certificate

To revoke a certificate, use 'sq key revoke' followed by <REASON> and <MESSAGE>:

$ sq key revoke --cert $FINGERPRINT --reason superseded --message 'there will be a new one'

To revoke a USER ID from a certificate, add the subcommand userid:

$ sq key userid revoke --cert $FINGERPRINT --userid 'alice' --reason retired --message 'testing_purposes'

The process is explained in more detail in this document: Chapter 'Revocation'

How to certify a User ID for a certificate

To create an exportable certification for a binding between a User ID and a certificate, use sq pki vouch certify. Note that the updated certificate should then be sent to the certificate holder to be approved and published.

$ sq pki vouch  certify --certifier $FP_CERTIFIER --cert $FP_TO_BE_CERTIFIED --email=bob@example.org

More information can be found here: Chapter 'Certifications'

How to mark a certificate as a trusted introducer

To mark an certificate as an exportable trust introducer (respectively a certificate authority) for the domain example.com with a preconfigured trust depth of one, use sq pki vouch authorize as follows:

$ sq pki vouch authorize --certifier $FPR_CERTIFIER --cert $FPR_TO_BE_CERTIFIED --domain=example.com

More information can be found here: Chapter 'Certify and authorize certificates'

How to approve a certification

To approve a certification which has been received by a third party, a keyholder can approve it by using the following command:

$ sq key approvals update --all --cert $FP_KEYHOLDER

Find more information here: Chapter 'Certify and authorize certificates'.