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.