sq, Sequoia PGP's CLI, Released

By Neal | January 26, 2021

Last month we released version 1.0 of our versatile, low-level OpenPGP library, sequoia-openpgp. Now we have released the first version of sq, version 0.23, which is meant for general use.

sq is a command-line tool that intends to expose much (but not all!) of the functionality that the library provides. Although we fully intend for sq to be an OpenPGP swiss army knife, and that the truly arcane should—in general—be possible, we firstly want sq to be usable by humans at the command line. We understand this to mean that it should be possible to use sq to tweak and twiddle OpenPGP data. But, those who have the desire to use Sequoia to frob it will need to use the library. And, they are probably better served by it anyway.

sq has a subcommand-style interface similar to git. This has the advantage that every command has its own option name space, which makes it much easier to understand exactly what options influence a given command.

In terms of functionality, sq already provides the base operations that any OpenPGP user needs in their day-to-day use: key generation (sq key generate), encryption (sq encrypt) & decryption (sq decrypt), signing (sq sign) & verification (sq verify), key certification (sq certify), and key server (sq keyserver) & web key directory (WKD) (sq wkd) interaction. It also includes some utility functions. It can generate a WKD (sq wkd generate), encode and decode Autocrypt headers (sq autocrypt), manipulate keyrings (sq keyring), inspect OpenPGP-related data like file does (sq inspect), and pretty print an OpenPGP file’s contents (sq packet dump).

sq is still missing a fair amount of functionality. In particular, there is no public or private key store. (Although prototypes exist.) This means all OpenPGP certificates must be stored in files, which is not scalable. Also, many necessary and useful commands are still missing. For instance, it is not currently possible to add new subkeys to a certificate, or change their expiration date.

sq is also not ready to be used from scripts. Although we are unlikely to change the current API, the bigger problem is that sq’s output is not machine readable. In the medium term, we plan to add a JSON-output mode to every command. Given the legion of JSON parsers, this should effectively eliminate the need for tools that consume sq’s output to have to parse it manually, and will hopefully eliminate an entire class of common security-sensitive bugs.

Until now, we haven’t published sq on crates.io, and we’ve discouraged packagers from including it in their distribution. We now think that sq is ready for general use. If you have suggestions, please reach out.

A Quick Demo

Creating an OpenPGP key is straightforward:

$ sq key generate --export /tmp/alice.sec -u 'Alice <alice@example.org>'

sq saves the key in /tmp/alice.sec and a generic revocation certificate in /tmp/alice.sec.rev.

We can use sq inspect to examine the new key’s structure:

$ sq inspect /tmp/alice.sec
/tmp/alice.sec: Transferable Secret Key.

    Fingerprint: 1191 7C40 2605 5EA3 4980  8877 C7C7 FF13 8025 22BE
Public-key algo: EdDSA Edwards-curve Digital Signature Algorithm
Public-key size: 256 bits
     Secret key: Unencrypted
  Creation time: 2021-01-25 19:17:42 UTC
Expiration time: 2024-01-26 12:44:03 UTC (creation time + P1095DT62781S)
      Key flags: certification

         Subkey: 0C61 2153 0ACF F0B2 C01E  6E8A 4D4D 029F 2206 7039
Public-key algo: EdDSA Edwards-curve Digital Signature Algorithm
Public-key size: 256 bits
     Secret key: Unencrypted
  Creation time: 2021-01-25 19:17:42 UTC
Expiration time: 2024-01-26 12:44:03 UTC (creation time + P1095DT62781S)
      Key flags: signing

         Subkey: F2CA 7FC7 A347 39F7 7CDC  C1F0 C599 64AB 43F7 7134
Public-key algo: ECDH public key algorithm
Public-key size: 256 bits
     Secret key: Unencrypted
  Creation time: 2021-01-25 19:17:42 UTC
Expiration time: 2024-01-26 12:44:03 UTC (creation time + P1095DT62781S)
      Key flags: transport encryption, data-at-rest encryption

         UserID: Alice <alice@example.org>

Here we see that sq uses ECC by default, and generates a signing subkey and an encryption subkey. (sq key generate has options to tweak both the cipher suite and the key’s structure.) sq generates a signing subkey by default to prevent an attacker from repurposing a signature over data as a certification or binding signature.

The secret key material is unencrypted by default. Supplying the --with-password option will cause sq to prompt for a password and use it to encrypt the secret key material.

We can use sq packet dump to get even more details:

$ sq packet dump /tmp/alice.sec
Secret-Key Packet, new CTB, 88 bytes
...
User ID Packet, new CTB, 25 bytes
    Value: Alice <alice@example.org>

Signature Packet, new CTB, 212 bytes
    Version: 4
    Type: PositiveCertification
    Pk algo: EdDSA Edwards-curve Digital Signature Algorithm
    Hash algo: SHA512
    Hashed area:
      Signature creation time: 2021-01-25 19:17:42 UTC (critical)
      Key expiration time: P1095DT62781S (critical)
      Symmetric algo preferences: AES256, AES128
      Issuer: C7C7 FF13 8025 22BE
      Notation: NotationData { flags: , name: "salt@notations.sequoia-pgp.org", value: [209, 99, ...] }
      Hash preferences: SHA512, SHA256
      Primary User ID: true (critical)
      Key flags: C (critical)
      Features: MDC
      Issuer Fingerprint: 1191 7C40 2605 5EA3 4980  8877 C7C7 FF13 8025 22BE
    Digest prefix: 7E0A
    Level: 0 (signature over data)
...

For the sake of brevity, I’ve only shown the User ID and the corresponding self signature. An interesting thing to note here is the salt@notations.sequoia-pgp.org notation. This is a random 32-byte value, which Sequoia inserts into every signature by default. Because it is unpredictable, it is harder for an attacker to trick a user into signing a specific message.

It is possible to get even more details by supplying the --hex option to sq packet dump. This causes it to print a descriptive map of the packets' contents, which is useful if you are dissecting an OpenPGP message.

$ sq packet dump --hex /tmp/alice.sec
Secret-Key Packet, new CTB, 2 header bytes + 88 bytes
    Version: 4
    Creation time: 2021-01-25 19:17:42 UTC
    Pk algo: EdDSA Edwards-curve Digital Signature Algorithm
    Pk size: 256 bits
    Fingerprint: 1191 7C40 2605 5EA3 4980  8877 C7C7 FF13 8025 22BE
    KeyID: C7C7 FF13 8025 22BE
  
    Secret Key:
  
        Unencrypted
  
    00000000  c5                                                 CTB
    00000001     58                                              length
    00000002        04                                           version
    00000003           60 0f 19 56                               creation_time
    00000007                       16                            pk_algo
    00000008                           09                        curve_len
    00000009                              2b 06 01 04 01 da 47   curve
    00000010  0f 01
    00000012        01 07                                        eddsa_public_len
    00000014              40 7b 06 00  4c 00 63 89 81 95 2f 22   eddsa_public
    00000020  5a 35 7c b2 84 45 ce 9f  d9 85 8d 55 01 4d aa 76
    00000030  f7 bd b2 07 a1
    00000035                 00                                  s2k_usage
    00000036                    00 fe                            eddsa_secret_len
    00000038                           30 95 9d a4 ae 95 c3 e4   eddsa_secret
    00000040  fc 15 bb ca 5a 67 31 e1  14 1b 2b 0b 2f 1a 4c 6e
    00000050  95 a8 cc 63 7c de 19 51 
    00000058                           0f ef                     checksum
...

To turn a key into a certificate (i.e., to remove the secret key material), we can use the sq keyring filter subcommand:

$ sq keyring filter --to-certificate /tmp/alice.sec > /tmp/alice.pgp

And using sq inspect, we see that we now have a certificate and not a secret key:

$ sq inspect /tmp/alice.pgp
/tmp/alice.pgp: OpenPGP Certificate.
...

sq keyring filter also allows the user to specify a few predicates to actually filter the keyring.

sq keyring has other useful functionality. It can split a keyring into individual keys and it can merge multiple keys or keyrings into a single keyring.

To sign and encrypt a message, we specify one or more certificates for the recipients, and one or more keys for the signers.

$ echo "Hello, woods!" | sq encrypt --recipient-cert /tmp/bob.pgp --signer-key /tmp/alice.sec > /tmp/msg.pgp

Decrypting and verifying the signature is similar:

$ sq decrypt --recipient-key /tmp/bob.sec --signer-cert /tmp/alice.pgp /tmp/msg.pgp
Encrypted using AES with 256-bit key
Compressed using ZIP
Good signature from 4D4D 029F 2206 7039
Hello, woods!
1 good signature.

(If you are interested in examining the structure of the message at the byte level, be sure to try the --hex option.)

sq can also fetch keys from key servers:

$ sq keyserver get neal@walfield.org
-----BEGIN PGP PUBLIC KEY BLOCK-----

xsEhBFUjmukBDqCpmVI7Ve+2xTFSTG+mXMFHml63/Yai2nqxBk9gBfQfRFIjMt74
...

And from WKDs:

$ sq wkd get neal@walfield.org
-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: 8F17 7771 18A3 3DDA 9BA4  8E62 AACB 3243 6300 52D9
Comment: Neal H. Walfield <neal@pep-project.org>
Comment: Neal H. Walfield <neal@pep.foundation>
Comment: Neal H. Walfield <neal@sequoia-pgp.org>
Comment: Neal H. Walfield <neal@walfield.org>

xsEhBFUjmukBDqCpmVI7Ve+2xTFSTG+mXMFHml63/Yai2nqxBk9gBfQfRFIjMt74
...

You can learn more about sq by reading its documentation.

Financial Support

Currently, six people are paid to work on Sequoia. Since the start of the project 3.5 years ago, they have all been paid by the p≡p foundation. Additional financial support has come from a one-time donation from the Wau Holland Foundation in 2018. Phil Zimmermann, the creator of PGP, donated 1000 Euros. And, Proton Mail donated 1000 Euros after our interoperability test suite found several issues in OpenPGP.js and GopenPGP, which they maintain.

Although the p≡p foundation’s finances are secure for the next half year, it is essential for Sequoia’s mid-term health that we obtain addition funding. You don’t need to directly use Sequoia to be positively impacted by it. For instance, OpenPGP CA is a new tool for creating federated CAs targeted at simplifying the use of OpenPGP for activists, lawyers, and journalists who can’t rely on centralized authentication solutions. So, consider donating. Of course, if your company is using Sequoia, consider sponsoring a developer (or two). Note: if you want to use Sequoia under a license other than the GPLv2+, please contact the foundation.

Thanks

Sequoia is a team effort. sq includes code contributions from Azul, Igor Matuszewski, Justus Winter, Neal H. Walfield, Nora Widdecke, and Wiktor Kwapisiewicz.