2017-12-13 10:54:03 +13:00
|
|
|
# Protecting code integrity with PGP
|
2017-12-05 10:46:02 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
Updated: 2021-05-13
|
2017-12-05 10:46:02 +13:00
|
|
|
|
2018-01-24 04:50:52 +13:00
|
|
|
*Status: CURRENT*
|
2017-12-14 10:44:35 +13:00
|
|
|
|
2020-05-10 18:55:22 +12:00
|
|
|
### Table of contents
|
|
|
|
|
|
|
|
- [Protecting code integrity with PGP](#protecting-code-integrity-with-pgp)
|
|
|
|
- [Table of contents](#table-of-contents)
|
|
|
|
- [Target audience](#target-audience)
|
|
|
|
- [Structure](#structure)
|
|
|
|
- [Checklist priority levels](#checklist-priority-levels)
|
|
|
|
- [Basic PGP concepts and tools](#basic-pgp-concepts-and-tools)
|
|
|
|
- [Checklist](#checklist)
|
|
|
|
- [Considerations](#considerations)
|
|
|
|
- [Extremely Basic Overview of PGP operations](#extremely-basic-overview-of-pgp-operations)
|
|
|
|
- [Encryption](#encryption)
|
|
|
|
- [Signatures](#signatures)
|
|
|
|
- [Combined usage](#combined-usage)
|
|
|
|
- [Understanding Key Identities](#understanding-key-identities)
|
|
|
|
- [Understanding Key Validity](#understanding-key-validity)
|
|
|
|
- [Web of Trust (WOT) vs. Trust on First Use (TOFU)](#web-of-trust-wot-vs-trust-on-first-use-tofu)
|
|
|
|
- [Installing OpenPGP software](#installing-openpgp-software)
|
|
|
|
- [Installing GnuPG](#installing-gnupg)
|
2021-05-14 04:41:52 +12:00
|
|
|
- [Generating and protecting your certification key](#generating-and-protecting-your-certification-key)
|
2020-05-10 18:55:22 +12:00
|
|
|
- [Checklist](#checklist-1)
|
|
|
|
- [Considerations](#considerations-1)
|
2021-05-14 04:41:52 +12:00
|
|
|
- [Understanding the certification key](#understanding-the-certification-key)
|
|
|
|
- [Before you create the certification key](#before-you-create-the-certification-key)
|
2020-05-10 18:55:22 +12:00
|
|
|
- [Primary identity](#primary-identity)
|
|
|
|
- [Passphrase](#passphrase)
|
|
|
|
- [Algorithm and key strength](#algorithm-and-key-strength)
|
2021-05-14 04:41:52 +12:00
|
|
|
- [Generate the certification key](#generate-the-certification-key)
|
|
|
|
- [Back up your certification key](#back-up-your-certification-key)
|
2020-05-10 18:55:22 +12:00
|
|
|
- [Add relevant identities](#add-relevant-identities)
|
|
|
|
- [Pick the primary UID](#pick-the-primary-uid)
|
|
|
|
- [Generating PGP subkeys](#generating-pgp-subkeys)
|
|
|
|
- [Checklist](#checklist-2)
|
|
|
|
- [Considerations](#considerations-2)
|
|
|
|
- [Create the subkeys](#create-the-subkeys)
|
2021-05-14 04:41:52 +12:00
|
|
|
- [Upload your public key to GitHub](#upload-your-public-key-to-github)
|
|
|
|
- [Moving your certification key to offline storage](#moving-your-certification-key-to-offline-storage)
|
2020-05-10 18:55:22 +12:00
|
|
|
- [Checklist](#checklist-3)
|
|
|
|
- [Considerations](#considerations-3)
|
|
|
|
- [Back up your GnuPG directory](#back-up-your-gnupg-directory)
|
|
|
|
- [Prepare detachable encrypted storage](#prepare-detachable-encrypted-storage)
|
|
|
|
- [Back up your GnuPG directory](#back-up-your-gnupg-directory-1)
|
2021-05-14 04:41:52 +12:00
|
|
|
- [Remove the certification key](#remove-the-certification-key)
|
|
|
|
- [Removing your certification key](#removing-your-certification-key)
|
2020-05-10 18:55:22 +12:00
|
|
|
- [Remove the revocation certificate](#remove-the-revocation-certificate)
|
|
|
|
- [Move the subkeys to a hardware device](#move-the-subkeys-to-a-hardware-device)
|
|
|
|
- [Checklist](#checklist-4)
|
|
|
|
- [Considerations](#considerations-4)
|
|
|
|
- [The benefits of smartcards](#the-benefits-of-smartcards)
|
|
|
|
- [Available smartcard devices](#available-smartcard-devices)
|
|
|
|
- [Configuring your smartcard device](#configuring-your-smartcard-device)
|
|
|
|
- [PINs don't have to be numbers](#pins-dont-have-to-be-numbers)
|
|
|
|
- [Quick setup](#quick-setup)
|
|
|
|
- [Moving the subkeys to your smartcard](#moving-the-subkeys-to-your-smartcard)
|
|
|
|
- [Verifying that the keys were moved](#verifying-that-the-keys-were-moved)
|
|
|
|
- [Verifying that the smartcard is functioning](#verifying-that-the-smartcard-is-functioning)
|
|
|
|
- [Other common GnuPG operations](#other-common-gnupg-operations)
|
2021-05-14 04:41:52 +12:00
|
|
|
- [Mounting your offline storage](#mounting-your-offline-storage)
|
2020-05-10 18:55:22 +12:00
|
|
|
- [Updating your regular GnuPG working directory](#updating-your-regular-gnupg-working-directory)
|
|
|
|
- [Extending key expiration date](#extending-key-expiration-date)
|
|
|
|
- [Revoking identities](#revoking-identities)
|
|
|
|
- [Using PGP with Git](#using-pgp-with-git)
|
|
|
|
- [Checklist](#checklist-5)
|
|
|
|
- [Considerations](#considerations-5)
|
|
|
|
- [Understanding Git Hashes](#understanding-git-hashes)
|
|
|
|
- [Tree hashes](#tree-hashes)
|
|
|
|
- [Commit hashes](#commit-hashes)
|
|
|
|
- [Hashing function](#hashing-function)
|
|
|
|
- [Annotated tags and tag signatures](#annotated-tags-and-tag-signatures)
|
|
|
|
- [Signed commits](#signed-commits)
|
|
|
|
- [Configure git to use your PGP key](#configure-git-to-use-your-pgp-key)
|
|
|
|
- [How to work with signed tags](#how-to-work-with-signed-tags)
|
|
|
|
- [How to verify signed tags](#how-to-verify-signed-tags)
|
|
|
|
- [Verifying at pull time](#verifying-at-pull-time)
|
|
|
|
- [Configure git to always sign annotated tags](#configure-git-to-always-sign-annotated-tags)
|
|
|
|
- [How to work with signed commits](#how-to-work-with-signed-commits)
|
|
|
|
- [How to verify signed commits](#how-to-verify-signed-commits)
|
|
|
|
- [Verifying commits during git merge](#verifying-commits-during-git-merge)
|
|
|
|
- [If your project uses mailing lists for patch management](#if-your-project-uses-mailing-lists-for-patch-management)
|
|
|
|
- [Configure git to always sign commits](#configure-git-to-always-sign-commits)
|
|
|
|
- [Configure gpg-agent options](#configure-gpg-agent-options)
|
|
|
|
- [Bonus: Using gpg-agent with ssh](#bonus-using-gpg-agent-with-ssh)
|
|
|
|
- [Protecting online accounts](#protecting-online-accounts)
|
|
|
|
- [Checklist](#checklist-6)
|
|
|
|
- [Considerations](#considerations-6)
|
|
|
|
- [Two-factor authentication with Fido U2F](#two-factor-authentication-with-fido-u2f)
|
|
|
|
- [Get a token capable of Fido U2F](#get-a-token-capable-of-fido-u2f)
|
|
|
|
- [Enable 2-factor authentication on your online accounts](#enable-2-factor-authentication-on-your-online-accounts)
|
|
|
|
- [Configure TOTP failover, if possible](#configure-totp-failover-if-possible)
|
|
|
|
- [Further reading](#further-reading)
|
|
|
|
|
2017-12-05 10:46:02 +13:00
|
|
|
### Target audience
|
|
|
|
|
|
|
|
This document is aimed at developers working on free software projects. It
|
|
|
|
covers the following topics:
|
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
1. PGP basics and best practices
|
|
|
|
2. How to use PGP with Git
|
|
|
|
3. How to protect your developer accounts
|
2017-12-05 10:46:02 +13:00
|
|
|
|
|
|
|
We use the term "Free" as in "Freedom," but this guide can also be used for
|
2018-01-26 10:50:44 +13:00
|
|
|
any other kind of software that relies on contributions from a distributed
|
|
|
|
team of developers. If you write code that goes into public source
|
|
|
|
repositories, you can benefit from getting acquainted with and following this
|
|
|
|
guide.
|
2017-12-05 10:46:02 +13:00
|
|
|
|
|
|
|
### Structure
|
|
|
|
|
|
|
|
Each section is split into two areas:
|
|
|
|
|
|
|
|
- The checklist that can be adapted to your project's needs
|
2017-12-08 09:53:50 +13:00
|
|
|
- Free-form list of considerations that explain what dictated these decisions,
|
|
|
|
together with configuration instructions
|
2017-12-05 10:46:02 +13:00
|
|
|
|
|
|
|
#### Checklist priority levels
|
|
|
|
|
|
|
|
The items in each checklist include the priority level, which we hope will
|
|
|
|
help guide your decision:
|
|
|
|
|
|
|
|
- _(ESSENTIAL)_ items should definitely be high on the consideration list.
|
|
|
|
If not implemented, they will introduce high risks to the code that gets
|
|
|
|
committed to the open-source project.
|
|
|
|
- _(NICE)_ to have items will improve the overall security, but will affect how
|
|
|
|
you interact with your work environment, and probably require learning new
|
|
|
|
habits or unlearning old ones.
|
|
|
|
|
|
|
|
Remember, these are only guidelines. If you feel these priority levels do not
|
|
|
|
reflect your project's commitment to security, you should adjust them as you
|
|
|
|
see fit.
|
|
|
|
|
2017-12-06 10:37:05 +13:00
|
|
|
## Basic PGP concepts and tools
|
|
|
|
|
|
|
|
### Checklist
|
|
|
|
|
|
|
|
- [ ] Understand the role of PGP in Free Software Development _(ESSENTIAL)_
|
|
|
|
- [ ] Understand the basics of Public Key Cryptography _(ESSENTIAL)_
|
|
|
|
- [ ] Understand PGP Encryption vs. Signatures _(ESSENTIAL)_
|
|
|
|
- [ ] Understand PGP key identities _(ESSENTIAL)_
|
|
|
|
- [ ] Understand PGP key validity _(ESSENTIAL)_
|
|
|
|
- [ ] Install GnuPG utilities (version 2.x) _(ESSENTIAL)_
|
|
|
|
|
|
|
|
### Considerations
|
2017-12-05 10:46:02 +13:00
|
|
|
|
|
|
|
The Free Software community has long relied on PGP for assuring the
|
|
|
|
authenticity and integrity of software products it produced. You may not be
|
|
|
|
aware of it, but whether you are a Linux, Mac or Windows user, you have
|
|
|
|
previously relied on PGP to ensure the integrity of your computing
|
|
|
|
environment:
|
|
|
|
|
|
|
|
- Linux distributions rely on PGP to ensure that binary or source packages have
|
|
|
|
not been altered between when they have been produced and when they are
|
|
|
|
installed by the end-user.
|
|
|
|
- Free Software projects usually provide detached PGP signatures to accompany
|
|
|
|
released software archives, so that downstream projects can verify the
|
|
|
|
integrity of downloaded releases before integrating them into their own
|
|
|
|
distributed downloads.
|
2017-12-06 10:37:05 +13:00
|
|
|
- Free Software projects routinely rely on PGP signatures within the code
|
2017-12-08 09:53:50 +13:00
|
|
|
itself in order to track provenance and verify integrity of code committed
|
2017-12-06 10:37:05 +13:00
|
|
|
by project developers.
|
2017-12-05 10:46:02 +13:00
|
|
|
|
|
|
|
This is very similar to developer certificates/code signing mechanisms used by
|
|
|
|
programmers working on proprietary platforms. In fact, the core concepts
|
|
|
|
behind these two technologies are very much the same -- they differ mostly in
|
|
|
|
the technical aspects of the implementation and the way they delegate trust.
|
|
|
|
PGP does not rely on centralized Certification Authorities, but instead lets
|
|
|
|
each user assign their own trust to each certificate.
|
|
|
|
|
2017-12-06 10:37:05 +13:00
|
|
|
Our goal is to get your project on board using PGP for code provenance and
|
|
|
|
integrity tracking, following best practices and observing basic security
|
|
|
|
precautions.
|
|
|
|
|
|
|
|
### Extremely Basic Overview of PGP operations
|
2017-12-05 10:46:02 +13:00
|
|
|
|
|
|
|
You do not need to know the exact details of how PGP works -- understanding
|
2017-12-06 10:37:05 +13:00
|
|
|
the core concepts is enough to be able to use it successfully for our
|
|
|
|
purposes. PGP relies on Public Key Cryptography to convert plain text into
|
|
|
|
encrypted text. This process requires two distinct keys:
|
2017-12-05 10:46:02 +13:00
|
|
|
|
2017-12-06 10:37:05 +13:00
|
|
|
- A public key that is _known to everyone_
|
|
|
|
- A private key that is _only known to the owner_
|
2017-12-05 10:46:02 +13:00
|
|
|
|
|
|
|
#### Encryption
|
|
|
|
|
|
|
|
For encryption, PGP uses the public key of the owner to create a message that
|
|
|
|
is only decryptable using the owner's private key:
|
|
|
|
|
|
|
|
1. the sender generates a random encryption key ("session key")
|
2017-12-15 09:08:16 +13:00
|
|
|
2. the sender encrypts the contents using that session key (using a symmetric
|
|
|
|
cipher)
|
2017-12-05 10:46:02 +13:00
|
|
|
3. the sender encrypts the session key using the recipient's _public_ PGP key
|
|
|
|
4. the sender sends both the encrypted contents and the encrypted session key
|
|
|
|
to the recipient
|
|
|
|
|
|
|
|
To decrypt:
|
|
|
|
|
|
|
|
1. the recipient decrypts the session key using their _private_ PGP key
|
|
|
|
2. the recipient uses the session key to decrypt the contents of the message
|
|
|
|
|
|
|
|
#### Signatures
|
|
|
|
|
|
|
|
For creating signatures, the private/public PGP keys are used the opposite way:
|
|
|
|
|
|
|
|
1. the signer generates the checksum hash of the contents
|
|
|
|
2. the signer uses their own _private_ PGP key to encrypt that checksum
|
|
|
|
3. the signer provides the encrypted checksum alongside the contents
|
|
|
|
|
|
|
|
To verify the signature:
|
|
|
|
|
|
|
|
1. the verifier generates their own checksum hash of the contents
|
|
|
|
2. the verifier uses the signer's _public_ PGP key to decrypt the provided
|
|
|
|
checksum
|
|
|
|
3. if the checksums match, the integrity of the contents is verified
|
|
|
|
|
|
|
|
#### Combined usage
|
|
|
|
|
|
|
|
Frequently, encrypted messages are also signed with the sender's own PGP key.
|
|
|
|
This should be the default whenever using encrypted messaging, as encryption
|
|
|
|
without authentication is not very meaningful (unless you are a whistleblower
|
2017-12-12 08:07:21 +13:00
|
|
|
or a secret agent and need plausible deniability).
|
2017-12-06 10:37:05 +13:00
|
|
|
|
|
|
|
### Understanding Key Identities
|
|
|
|
|
|
|
|
Each PGP key must have one or multiple Identities associated with it. Usually,
|
|
|
|
an "Identity" is the person's full name and email address in the following
|
|
|
|
format:
|
|
|
|
|
|
|
|
Alice Engineer <alice.engineer@example.com>
|
|
|
|
|
|
|
|
Sometimes it will also contain a comment in brackets, to tell the end-user
|
|
|
|
more about that particular key:
|
|
|
|
|
|
|
|
Bob Designer (obsolete 1024-bit key) <bob.designer@example.com>
|
|
|
|
|
|
|
|
Since people can be associated with multiple professional and personal
|
|
|
|
entities, they can have multiple identities on the same key:
|
|
|
|
|
|
|
|
Alice Engineer <alice.engineer@example.com>
|
|
|
|
Alice Engineer <aengineer@personalmail.example.org>
|
|
|
|
Alice Engineer <webmaster@girlswhocode.example.net>
|
|
|
|
|
|
|
|
When multiple identities are used, one of them would be marked as the "primary
|
|
|
|
identity" to make searching easier.
|
|
|
|
|
|
|
|
### Understanding Key Validity
|
|
|
|
|
|
|
|
To be able to use someone else's public key for encryption or verification,
|
|
|
|
you need to be sure that it actually belongs to the right person (Alice) and
|
|
|
|
not to an impostor (Eve). In PGP, this certainty is called "key validity:"
|
|
|
|
|
|
|
|
- **Validity: full** -- means we are pretty sure this key belongs to Alice
|
|
|
|
- **Validity: marginal** -- means we are *somewhat* sure this key belongs to
|
|
|
|
Alice
|
2017-12-15 09:08:16 +13:00
|
|
|
- **Validity: unknown** -- means there is no assurance at all that this key
|
2017-12-06 10:37:05 +13:00
|
|
|
belongs to Alice
|
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
#### Web of Trust (WOT) vs. Trust on First Use (TOFU)
|
2017-12-06 10:37:05 +13:00
|
|
|
|
2017-12-12 08:07:21 +13:00
|
|
|
PGP incorporates a trust delegation mechanism known as the "Web of Trust." At
|
|
|
|
its core, this is an attempt to replace the need for centralized Certification
|
2017-12-06 10:37:05 +13:00
|
|
|
Authorities of the HTTPS/TLS world. Instead of various software makers
|
2017-12-12 08:07:21 +13:00
|
|
|
dictating who should be your trusted certifying entity, PGP leaves this
|
|
|
|
responsibility to each user.
|
2017-12-06 10:37:05 +13:00
|
|
|
|
|
|
|
Unfortunately, very few people understand how the Web of Trust works, and even
|
|
|
|
fewer bother to keep it going. It remains an important aspect of the OpenPGP
|
|
|
|
specification, but recent versions of GnuPG (2.2 and above) have implemented
|
|
|
|
an alternative mechanism called "Trust on First Use" (TOFU).
|
|
|
|
|
|
|
|
You can think of TOFU as "the SSH-like approach to trust." With SSH, the first
|
|
|
|
time you connect to a remote system, its key fingerprint is recorded and
|
|
|
|
remembered. If the key changes in the future, the SSH client will alert you
|
|
|
|
and refuse to connect, forcing you to make a decision on whether you choose to
|
|
|
|
trust the changed key or not.
|
|
|
|
|
|
|
|
Similarly, the first time you import someone's PGP key, it is assumed to be
|
|
|
|
trusted. If at any point in the future GnuPG comes across another key with the
|
|
|
|
same identity, both the previously imported key and the new key will be marked
|
2017-12-12 08:07:21 +13:00
|
|
|
as invalid and you will need to manually figure out which one to keep.
|
2017-12-06 10:37:05 +13:00
|
|
|
|
|
|
|
In this guide, we will be using the TOFU trust model.
|
|
|
|
|
|
|
|
### Installing OpenPGP software
|
|
|
|
|
|
|
|
First, it is important to understand the distinction between PGP, OpenPGP,
|
|
|
|
GnuPG and gpg:
|
|
|
|
|
2018-01-19 10:32:31 +13:00
|
|
|
- **PGP** ("Pretty Good Privacy") is the name of the original commercial
|
|
|
|
software
|
2017-12-06 10:37:05 +13:00
|
|
|
- **OpenPGP** is the IETF standard compatible with the original PGP tool
|
|
|
|
- **GnuPG** ("Gnu Privacy Guard") is free software that implements the OpenPGP
|
|
|
|
standard
|
|
|
|
- The command-line tool for GnuPG is called "**gpg**"
|
|
|
|
|
2017-12-08 09:53:50 +13:00
|
|
|
Today, the term "PGP" is almost universally used to mean "the OpenPGP
|
|
|
|
standard," not the original commercial software, and therefore "PGP" and
|
|
|
|
"OpenPGP" are interchangeable. The terms "GnuPG" and "gpg" should only be used
|
|
|
|
when referring to the tools, not to the output they produce or OpenPGP
|
|
|
|
features they implement. For example:
|
2017-12-06 10:37:05 +13:00
|
|
|
|
|
|
|
- PGP (not GnuPG or GPG) key
|
|
|
|
- PGP (not GnuPG or GPG) signature
|
|
|
|
- PGP (not GnuPG or GPG) keyserver
|
|
|
|
|
|
|
|
Understanding this should protect you from an inevitable pedantic "actually"
|
|
|
|
from other PGP users you come across.
|
|
|
|
|
|
|
|
#### Installing GnuPG
|
|
|
|
|
|
|
|
If you are using Linux, you should already have GnuPG installed. On a Mac,
|
2017-12-07 11:07:14 +13:00
|
|
|
you should install [GPG-Suite](https://gpgtools.org) or you can use `brew
|
2017-12-19 02:28:38 +13:00
|
|
|
install gnupg2`. On a Windows PC, you should install
|
|
|
|
[GPG4Win](https://www.gpg4win.org), and you will probably need to adjust some
|
|
|
|
of the commands in the guide to work for you, unless you have a unix-like
|
|
|
|
environment set up. For all other platforms, you'll need to do your own
|
|
|
|
research to find the correct places to download and install GnuPG.
|
2017-12-06 10:37:05 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
## Generating and protecting your certification key
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
### Checklist
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
- [ ] Generate a 4096-bit RSA certification key _(ESSENTIAL)_
|
|
|
|
- [ ] Back up the certification key using paperkey _(ESSENTIAL)_
|
2017-12-07 11:07:14 +13:00
|
|
|
- [ ] Add all relevant identities _(ESSENTIAL)_
|
|
|
|
|
|
|
|
### Considerations
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
#### Understanding the certification key
|
|
|
|
|
|
|
|
In this and next section we'll talk about the certification key and subkeys.
|
|
|
|
The certification key is often called "the master key," but it is a poor
|
|
|
|
analogy, as it doesn't act in any way like a physical master key (in the sense
|
|
|
|
that it cannot decrypt content encrypted to any of the subkeys, as one
|
|
|
|
example). For this reason, we'll stick to calling it the "certification key."
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
It is important to understand the following:
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
1. There are no technical differences between the certify key and any of the
|
|
|
|
subkeys
|
2017-12-07 11:07:14 +13:00
|
|
|
2. At creation time, we assign functional limitations to each key by
|
|
|
|
giving it specific capabilities.
|
2021-05-14 04:41:52 +12:00
|
|
|
3. A PGP key can have 4 capabilities:
|
2017-12-08 09:53:50 +13:00
|
|
|
- **[S]** key can be used for signing
|
|
|
|
- **[E]** key can be used for encryption
|
|
|
|
- **[A]** key can be used for authentication
|
|
|
|
- **[C]** key can be used for certifying other keys
|
2017-12-07 11:07:14 +13:00
|
|
|
4. A single key may have multiple capabilities.
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
The key carrying the **[C]** (certify) capability is used to indicate
|
|
|
|
relationship with other PGP keys. Only the **[C]** key can be used to:
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
- add or revoke other keys (subkeys) with S/E/A capabilities
|
|
|
|
- add, change or revoke identities (uids) associated with the key
|
|
|
|
- add or change the expiration date on itself or any subkey
|
|
|
|
- sign other people's keys for the web of trust purposes
|
|
|
|
|
|
|
|
In the Free Software world, the **[C]** key is your digital identity. Once you
|
2018-01-24 04:50:52 +13:00
|
|
|
create that key, you should take extra care to protect it and prevent it from
|
2017-12-07 11:07:14 +13:00
|
|
|
falling into malicious hands.
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
#### Before you create the certify key
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
Before you create your certify key you need to pick your primary identity and
|
|
|
|
your passphrase.
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
##### Primary identity
|
|
|
|
|
2018-01-24 04:50:52 +13:00
|
|
|
Identities are strings using the same format as the "From" field in emails:
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
Alice Engineer <alice.engineer@example.org>
|
|
|
|
|
2017-12-08 09:53:50 +13:00
|
|
|
You can create new identities, revoke old ones, and change which identity is
|
|
|
|
your "primary" one at any time. Since the primary identity is shown in all
|
|
|
|
GnuPG operations, you should pick a name and address that are both
|
2017-12-12 08:07:21 +13:00
|
|
|
professional and the most likely ones to be used for PGP-protected
|
2017-12-08 09:53:50 +13:00
|
|
|
communication, such as your work address or the address you use for signing
|
|
|
|
off on project commits.
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
##### Passphrase
|
|
|
|
|
|
|
|
The passphrase is used exclusively for encrypting the private key with a
|
|
|
|
symmetric algorithm while it is stored on disk. If the contents of your
|
|
|
|
`.gnupg` directory ever get leaked, a good passphrase is the last line of
|
|
|
|
defense between the thief and them being able to impersonate you online, which
|
|
|
|
is why it is important to set up a good passphrase.
|
|
|
|
|
|
|
|
A good guideline for a strong passphrase is 3-4 words from a rich or mixed
|
|
|
|
dictionary that are not quotes from popular sources (songs, books, slogans).
|
2017-12-08 09:53:50 +13:00
|
|
|
You'll be using this passphrase fairly frequently, so it should be both easy
|
|
|
|
to type and easy to remember.
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
##### Algorithm and key strength
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
GnuPG supports many algorithms, but we will only consider the below two:
|
|
|
|
|
|
|
|
- RSA for the certification key
|
|
|
|
- ECC (Elliptic Curve) for all other subkeys
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
We use RSA for the certification key mainly for compatibility reasons -- there
|
|
|
|
is probably still some tooling that does not properly handle ECC keys, so
|
|
|
|
sticking with RSA for the certification key makes sense. We will use it only
|
|
|
|
very occasionally, so the slowness/size considerations are unimportant.
|
2017-12-19 02:28:38 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
All of the day-to-day work will be done using subkeys, so picking ECC makes
|
|
|
|
perfect sense there -- it will be faster and the resulting signatures will be
|
|
|
|
dramatically smaller.
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
#### Generate the certification key
|
|
|
|
|
|
|
|
To generate your new certification key, issue the following command, putting
|
|
|
|
in the right values instead of "Alice Engineer:"
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2017-12-08 09:53:50 +13:00
|
|
|
$ gpg --quick-generate-key 'Alice Engineer <alice@example.org>' rsa4096 cert
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
A dialog will pop up asking to enter the passphrase. Then, you may need to
|
|
|
|
move your mouse around or type on some keys to generate enough entropy until
|
|
|
|
the command completes.
|
|
|
|
|
|
|
|
Review the output of the command, it will be something like this:
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
pub rsa4096 2021-05-01 [C] [expires: 2023-05-01]
|
2017-12-07 11:07:14 +13:00
|
|
|
111122223333444455556666AAAABBBBCCCCDDDD
|
|
|
|
uid Alice Engineer <alice@example.org>
|
|
|
|
|
|
|
|
Note the long string on the 2nd line -- that is the full fingerprint of your
|
2017-12-08 09:53:50 +13:00
|
|
|
newly generated key. Key IDs can be represented in three different forms:
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
- **fingerprint**, a full 40-character key identifier
|
|
|
|
- **long**, last 16-characters of the fingerprint (`AAAABBBBCCCCDDDD`)
|
|
|
|
- **short**, last 8 characters of the fingerprint (`CCCCDDDD`)
|
|
|
|
|
|
|
|
You should avoid using 8-character "short key IDs" as they are not
|
|
|
|
sufficiently unique.
|
|
|
|
|
|
|
|
At this point, I suggest you open a text editor, copy the fingerprint of your
|
2017-12-12 08:07:21 +13:00
|
|
|
new key and paste it there. You'll need to use it for the next few steps, so
|
|
|
|
having it close by will be handy.
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
#### Back up your certification key
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
For disaster recovery purposes -- and especially if you intend to use the Web
|
|
|
|
of Trust and collect key signatures from other project developers -- you
|
2017-12-12 08:07:21 +13:00
|
|
|
should create a hardcopy backup of your private key. This is supposed to be
|
|
|
|
the "last resort" measure in case all other backup mechanisms have failed.
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2017-12-08 09:53:50 +13:00
|
|
|
The best way to create a printable hardcopy of your private key is using the
|
2017-12-07 11:07:14 +13:00
|
|
|
`paperkey` software written for this very purpose. Paperkey is available on
|
2017-12-08 09:53:50 +13:00
|
|
|
all Linux distros, as well as installable via `brew install paperkey` on Macs.
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
Run the following command, replacing `[fpr]` with the full fingerprint of your
|
|
|
|
key:
|
|
|
|
|
2018-02-01 14:40:03 +13:00
|
|
|
$ gpg --export-secret-key [fpr] | paperkey -o /tmp/key-backup.txt
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
The output will be in a format that is easy to OCR or input by hand, should
|
|
|
|
you ever need to recover it. Print out that file, then take a pen and write
|
2017-12-12 08:07:21 +13:00
|
|
|
the key passphrase on the margin of the paper. **This is a required step**
|
|
|
|
because the key printout is still encrypted with the passphrase, and if you
|
|
|
|
ever change the passphrase on your key, you will not remember what it used to
|
|
|
|
be when you had first created it -- *guaranteed*.
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
Put the resulting printout and the hand-written passphrase into an envelope
|
2017-12-12 08:07:21 +13:00
|
|
|
and store in a secure and well-protected place, preferably away from your
|
|
|
|
home, such as your bank vault.
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
**NOTE ON PRINTERS**: Long gone are days when printers were dumb devices
|
2017-12-08 09:53:50 +13:00
|
|
|
connected to your computer's parallel port. These days they have full
|
|
|
|
operating systems, hard drives, and cloud integration. Since the key content
|
|
|
|
we send to the printer will be encrypted with the passphrase, this is a fairly
|
|
|
|
safe operation, but use your best paranoid judgement.
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
#### Add relevant identities
|
|
|
|
|
|
|
|
If you have multiple relevant email addresses (personal, work, open-source
|
2021-05-14 04:41:52 +12:00
|
|
|
project, etc), you should add them to your key. You don't need to do this for
|
|
|
|
any addresses that you don't expect to use with PGP (e.g. probably not your
|
|
|
|
school alumni address).
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
The command is (put the full key fingerprint instead of `[fpr]`):
|
|
|
|
|
2017-12-08 09:53:50 +13:00
|
|
|
$ gpg --quick-add-uid [fpr] 'Alice Engineer <allie@example.net>'
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
You can review the UIDs you've already added using:
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2017-12-08 09:53:50 +13:00
|
|
|
$ gpg --list-key [fpr] | grep ^uid
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
##### Pick the primary UID
|
|
|
|
|
|
|
|
GnuPG will make the latest UID you add as your primary UID, so if that is
|
|
|
|
different from what you want, you should fix it back:
|
|
|
|
|
2017-12-08 09:53:50 +13:00
|
|
|
$ gpg --quick-set-primary-uid [fpr] 'Alice Engineer <alice@example.org>'
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
## Generating PGP subkeys
|
|
|
|
|
|
|
|
### Checklist
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
- [ ] Generate the Encryption subkey _(ESSENTIAL)_
|
|
|
|
- [ ] Generate the Signing subkey _(ESSENTIAL)_
|
|
|
|
- [ ] Generate the Authentication subkey _(NICE)_
|
|
|
|
- [ ] Upload your public keys to a PGP keyserver _(NICE)_
|
|
|
|
- [ ] Set up a refresh cronjob _(NICE)_
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
### Considerations
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
Now that we've created the certification key, let's create the keys you'll
|
|
|
|
actually be using for day-to-day work. Before we do this, we need to pick the
|
|
|
|
ECC algorithm flavor.
|
|
|
|
|
|
|
|
#### ED25519 or NIST?
|
|
|
|
|
|
|
|
We won't go into the reasons behind why ECC is split into two camps. All you
|
|
|
|
need to know is that many people consider ed25519 "more pure" due to the way
|
|
|
|
its underlying curve primitives were selected and NIST "less pure" because
|
|
|
|
that selection process was not as public or thorough.
|
|
|
|
|
|
|
|
Do you plan to use a hardware device like a Yubikey for storing your subkeys?
|
|
|
|
Then pick NIST (use "nistp256" instead of "cv25519" and "ed25519" below). If
|
|
|
|
you just plan to store your subkeys on your computer, then pick ED25519 (the
|
|
|
|
GnuPG default).
|
|
|
|
|
|
|
|
Since you can revoke subkeys and create new ones at any time, this is not a
|
|
|
|
life or death kind of decision. If in doubt, pick ed25519.
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2017-12-08 09:53:50 +13:00
|
|
|
#### Create the subkeys
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
To create the subkeys, run:
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
$ gpg --quick-add-key [fpr] cv25519 encr
|
|
|
|
$ gpg --quick-add-key [fpr] ed25519 sign
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
You can also create the Authentication key, which will allow you to use your
|
2017-12-15 09:08:16 +13:00
|
|
|
PGP key for ssh purposes:
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
$ gpg --quick-add-key [fpr] ed25519 auth
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
You can review your key information using `gpg --list-key [fpr]`:
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
pub rsa4096 2021-05-01 [C] [expires: 2023-05-01]
|
2017-12-07 11:07:14 +13:00
|
|
|
111122223333444455556666AAAABBBBCCCCDDDD
|
|
|
|
uid [ultimate] Alice Engineer <alice@example.org>
|
|
|
|
uid [ultimate] Alice Engineer <allie@example.net>
|
2021-05-14 04:41:52 +12:00
|
|
|
sub cv25519 2021-05-01 [E]
|
|
|
|
sub ed25519 2021-05-01 [S]
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
#### Upload your public key to GitHub
|
2017-12-08 09:53:50 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
If you use GitHub in your development, you should upload your key following
|
|
|
|
the instructions they have provided:
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
- [Adding a PGP key to your GitHub account](https://help.github.com/articles/adding-a-new-gpg-key-to-your-github-account/)
|
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
To generate the public key output suitable to paste in, just run:
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
$ gpg --export --armor [fpr]
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
#### Upload your public key to keys.openpgp.org
|
2017-12-13 10:54:03 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
To make it easier for others to find your public key, you can upload it to the
|
|
|
|
keys.openpgp.org keyserver. Please follow the instructions provided here:
|
2017-12-13 10:54:03 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
- [Upload to keys.openpgp.org](https://keys.openpgp.org/about/usage#gnupg-upload)
|
2017-12-13 10:54:03 +13:00
|
|
|
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
## Moving your cerification key to offline storage
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
### Checklist
|
|
|
|
|
|
|
|
- [ ] Prepare encrypted detachable storage _(ESSENTIAL)_
|
|
|
|
- [ ] Back up your GnuPG directory _(ESSENTIAL)_
|
2021-05-14 04:41:52 +12:00
|
|
|
- [ ] Remove the certification key from your home directory _(NICE)_
|
2017-12-08 09:53:50 +13:00
|
|
|
- [ ] Remove the revocation certificate from your home directory _(NICE)_
|
|
|
|
|
|
|
|
### Considerations
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
Why would you want to remove your certification (**[C]**) key from your home
|
|
|
|
directory? This is generally done to prevent it from being stolen or
|
|
|
|
accidentally leaked. Private keys are tasty targets for malicious actors --
|
|
|
|
we know this from several successful malware attacks that scanned users' home
|
2017-12-08 09:53:50 +13:00
|
|
|
directories and uploaded any private key content found there.
|
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
It would be very damaging for any developer to have their PGP keys stolen --
|
2021-05-14 04:41:52 +12:00
|
|
|
in the Free Software world this is basically equal to identity theft.
|
2017-12-15 09:08:16 +13:00
|
|
|
Removing private keys from your home directory helps protect you from such
|
|
|
|
events.
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
#### Back up your GnuPG directory
|
|
|
|
|
2017-12-08 09:53:50 +13:00
|
|
|
**!!!Do not skip this step!!!**
|
|
|
|
|
2017-12-07 11:07:14 +13:00
|
|
|
It is important to have a readily available backup of your PGP keys should you
|
|
|
|
need to recover them (this is different from the disaster-level preparedness
|
|
|
|
we did with `paperkey`).
|
|
|
|
|
|
|
|
#### Prepare detachable encrypted storage
|
|
|
|
|
2017-12-12 08:07:21 +13:00
|
|
|
Start by getting a small USB "thumb" drive (preferably two!) that you will use
|
2017-12-08 09:53:50 +13:00
|
|
|
for backup purposes. You will first need to encrypt them:
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
- [Apple instructions](https://support.apple.com/kb/PH25745)
|
|
|
|
- [Linux instructions](https://help.ubuntu.com/community/EncryptedFilesystemsOnRemovableStorage)
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
For the encryption passphrase, you can use the same one as on your private
|
|
|
|
key.
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
#### Back up your GnuPG directory
|
|
|
|
|
|
|
|
Once the encryption process is over, re-insert the USB drive and make sure it
|
|
|
|
gets properly mounted. Find out the full mount point of the device, for
|
|
|
|
example by running the `mount` command (under Linux, external media usually
|
|
|
|
gets mounted under `/media/disk`, under Mac it's `/Volumes`).
|
|
|
|
|
|
|
|
Once you know the full mount path, copy your entire GnuPG directory there:
|
|
|
|
|
2017-12-15 20:15:11 +13:00
|
|
|
$ cp -rp ~/.gnupg [/media/disk/name]/gnupg-backup
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2017-12-19 02:32:17 +13:00
|
|
|
(Note: If you get any `Operation not supported on socket` errors, those are
|
|
|
|
benign and you can ignore them.)
|
|
|
|
|
|
|
|
You should now test to make sure everything still works:
|
2017-12-07 11:07:14 +13:00
|
|
|
|
2017-12-08 09:53:50 +13:00
|
|
|
$ gpg --homedir=[/media/disk/name]/gnupg-backup --list-key [fpr]
|
2017-12-07 11:07:14 +13:00
|
|
|
|
|
|
|
If you don't get any errors, then you should be good to go. Unmount the USB
|
2017-12-08 09:53:50 +13:00
|
|
|
drive, distinctly label it so you don't blow it away next time you need to use
|
|
|
|
a random USB drive, and put in a safe place -- but not too far away, because
|
2017-12-15 09:08:16 +13:00
|
|
|
you'll need to use it every now and again for things like editing identities,
|
|
|
|
adding or revoking subkeys, or signing other people's keys.
|
2017-12-08 09:53:50 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
#### Remove the certification key
|
2017-12-08 09:53:50 +13:00
|
|
|
|
2018-01-26 05:54:52 +13:00
|
|
|
The files in our home directory are not as well protected as we like to think.
|
|
|
|
They can be leaked or stolen via many different means:
|
|
|
|
|
|
|
|
- by accident when making quick homedir copies to set up a new workstation
|
|
|
|
- by systems administrator negligence or malice
|
|
|
|
- via poorly secured backups
|
|
|
|
- via malware in desktop apps (browsers, pdf viewers, etc)
|
|
|
|
- via coercion when crossing international borders
|
|
|
|
|
|
|
|
Protecting your key with a good passphrase greatly helps reduce the risk of
|
|
|
|
any of the above, but passphrases can be discovered via keyloggers,
|
|
|
|
shoulder-surfing, or any number of other means. For this reason, the
|
2021-05-14 04:41:52 +12:00
|
|
|
recommended setup is to remove your certification key from your home directory
|
|
|
|
and store it on offline storage.
|
2018-01-26 05:54:52 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
##### Removing your certification key
|
2018-01-26 05:54:52 +13:00
|
|
|
|
2017-12-08 09:53:50 +13:00
|
|
|
Please see the previous section and make sure you have backed up your GnuPG
|
2017-12-19 02:32:17 +13:00
|
|
|
directory in its entirety. What we are about to do will render your key
|
|
|
|
useless if you do not have a usable backup!
|
2017-12-08 09:53:50 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
First, identify the "keygrip" of your certification key:
|
2017-12-08 09:53:50 +13:00
|
|
|
|
|
|
|
$ gpg --with-keygrip --list-key [fpr]
|
|
|
|
|
|
|
|
The output will be something like this:
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
pub rsa4096 2021-05-01 [C] [expires: 2023-05-01]
|
2017-12-08 09:53:50 +13:00
|
|
|
111122223333444455556666AAAABBBBCCCCDDDD
|
|
|
|
Keygrip = AAAA999988887777666655554444333322221111
|
|
|
|
uid [ultimate] Alice Engineer <alice@example.org>
|
|
|
|
uid [ultimate] Alice Engineer <allie@example.net>
|
2021-05-14 04:41:52 +12:00
|
|
|
sub cv25519 2021-05-01 [E]
|
2017-12-08 09:53:50 +13:00
|
|
|
Keygrip = BBBB999988887777666655554444333322221111
|
2021-05-14 04:41:52 +12:00
|
|
|
sub ed25519 2021-05-01 [S]
|
2017-12-08 09:53:50 +13:00
|
|
|
Keygrip = CCCC999988887777666655554444333322221111
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
Find the keygrip entry that is beneath the `pub` line (right under the public
|
2017-12-08 09:53:50 +13:00
|
|
|
key fingerprint). This will correspond directly to a file in your home
|
|
|
|
`.gnupg` directory:
|
|
|
|
|
|
|
|
$ cd ~/.gnupg/private-keys-v1.d
|
|
|
|
$ ls
|
|
|
|
AAAA999988887777666655554444333322221111.key
|
|
|
|
BBBB999988887777666655554444333322221111.key
|
|
|
|
CCCC999988887777666655554444333322221111.key
|
|
|
|
|
|
|
|
All you have to do is simply remove the `.key` file that corresponds to the
|
2021-05-14 04:41:52 +12:00
|
|
|
certification keygrip:
|
2017-12-08 09:53:50 +13:00
|
|
|
|
|
|
|
$ cd ~/.gnupg/private-keys-v1.d
|
|
|
|
$ rm AAAA999988887777666655554444333322221111.key
|
|
|
|
|
2018-01-24 04:50:52 +13:00
|
|
|
Now, if you issue the `--list-secret-keys` command, it will show that the
|
2021-05-14 04:41:52 +12:00
|
|
|
**[C]** key is not present (indicated by the `#` character):
|
2017-12-08 09:53:50 +13:00
|
|
|
|
|
|
|
$ gpg --list-secret-keys
|
2021-05-14 04:41:52 +12:00
|
|
|
sec# rsa4096 2021-05-01 [C] [expires: 2023-05-01]
|
2017-12-08 09:53:50 +13:00
|
|
|
111122223333444455556666AAAABBBBCCCCDDDD
|
|
|
|
uid [ultimate] Alice Engineer <alice@example.org>
|
|
|
|
uid [ultimate] Alice Engineer <allie@example.net>
|
2021-05-14 04:41:52 +12:00
|
|
|
ssb cv25519 2021-05-01 [E]
|
|
|
|
ssb ed25519 2021-05-01 [S]
|
2017-12-08 09:53:50 +13:00
|
|
|
|
|
|
|
#### Remove the revocation certificate
|
|
|
|
|
|
|
|
Another file you should remove (but keep in backups) is the revocation
|
2021-05-14 04:41:52 +12:00
|
|
|
certificate that was automatically created with your certification key. A
|
|
|
|
revocation certificate allows someone to permanently mark your key as revoked,
|
|
|
|
meaning it can no longer be used or trusted for any purpose. You would
|
|
|
|
normally use it to revoke a key that, for some reason, you can no longer
|
|
|
|
control -- for example, if you had lost the key passphrase.
|
2017-12-08 09:53:50 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
Just as with the certification key, if a revocation certificate leaks into
|
|
|
|
malicious hands, it can be used to destroy your developer digital identity, so
|
|
|
|
it's better to remove it from your home directory.
|
2017-12-08 09:53:50 +13:00
|
|
|
|
|
|
|
cd ~/.gnupg/openpgp-revocs.d
|
|
|
|
rm [fpr].rev
|
|
|
|
|
|
|
|
## Move the subkeys to a hardware device
|
|
|
|
|
|
|
|
### Checklist
|
|
|
|
|
|
|
|
- [ ] Get a GnuPG-compatible hardware device _(NICE)_
|
|
|
|
- [ ] Configure the device to work with GnuPG _(NICE)_
|
|
|
|
- [ ] Set the user and admin PINs _(NICE)_
|
|
|
|
- [ ] Move your subkeys to the device _(NICE)_
|
|
|
|
|
|
|
|
### Considerations
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
Even though the certification key is now safe from being leaked or stolen, the
|
2018-01-26 05:54:52 +13:00
|
|
|
subkeys are still in your home directory. Anyone who manages to get their
|
|
|
|
hands on those will be able to decrypt your communication or fake your
|
|
|
|
signatures (if they know the passphrase). Furthermore, each time a GnuPG
|
|
|
|
operation is performed, the keys are loaded into system memory and can be
|
|
|
|
stolen from there by sufficiently advanced malware (think Meltdown and
|
|
|
|
Spectre).
|
2017-12-08 09:53:50 +13:00
|
|
|
|
|
|
|
The best way to completely protect your keys is to move them to a specialized
|
|
|
|
hardware device that is capable of smartcard operations.
|
|
|
|
|
|
|
|
#### The benefits of smartcards
|
|
|
|
|
|
|
|
A smartcard contains a cryptographic chip that is capable of storing private
|
|
|
|
keys and performing crypto operations directly on the card itself. Because the
|
|
|
|
key contents never leave the smartcard, the operating system of the computer
|
|
|
|
into which you plug in the hardware device is not able to retrieve the
|
|
|
|
private keys themselves. This is very different from the encrypted USB storage
|
|
|
|
device we used earlier for backup purposes -- while that USB device is plugged
|
|
|
|
in and decrypted, the operating system is still able to access the private key
|
|
|
|
contents. Using external encrypted USB media is not a substitute to having a
|
|
|
|
smartcard-capable device.
|
|
|
|
|
|
|
|
Some other benefits of smartcards:
|
|
|
|
|
|
|
|
- they are relatively cheap and easy to obtain
|
|
|
|
- they are small and easy to carry with you
|
|
|
|
- they can be used with multiple devices
|
|
|
|
- many of them are tamper-resistant (depends on manufacturer)
|
|
|
|
|
|
|
|
#### Available smartcard devices
|
|
|
|
|
|
|
|
Smartcards started out embedded into actual wallet-sized cards, which earned
|
|
|
|
them their name. You can still buy and use GnuPG-capable smartcards, and they
|
|
|
|
remain one of the cheapest available devices you can get. However, actual
|
|
|
|
smartcards have one important downside: they require a smartcard reader, and
|
|
|
|
very few laptops come with one.
|
|
|
|
|
|
|
|
For this reason, manufacturers have started providing small USB devices, the
|
|
|
|
size of a USB thumb drive or smaller, that either have the microsim-sized
|
|
|
|
smartcard pre-inserted, or that simply implement the smartcard protocol
|
|
|
|
features on the internal chip. Here are a few recommendations:
|
|
|
|
|
|
|
|
- [Nitrokey Start](https://shop.nitrokey.com/shop/product/nitrokey-start-6):
|
|
|
|
Open hardware and Free Software: one of the cheapest options for GnuPG use,
|
2021-05-14 04:41:52 +12:00
|
|
|
but with fewest extra security features.
|
2017-12-08 09:53:50 +13:00
|
|
|
- [Nitrokey Pro](https://shop.nitrokey.com/shop/product/nitrokey-pro-3):
|
|
|
|
Similar to the Nitrokey Start, but is tamper-resistant and offers more
|
2021-05-14 04:41:52 +12:00
|
|
|
security features (but not U2F, see the Fido U2F section of the guide); only
|
|
|
|
supports NIST ECC cryptography.
|
|
|
|
- [Yubikey](https://www.yubico.com/): Proprietary hardware and software, but
|
|
|
|
cheaper than Nitrokey Pro and comes available in the USB-C form that is more
|
|
|
|
useful with newer laptops; also offers additional security features such as
|
|
|
|
U2F; only supports NIST ECC cryptography.
|
2017-12-08 09:53:50 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
If you want to use ED25519 subkeys, then your only choice is a Nitrokey Start,
|
|
|
|
though once Nitrokey 3 Pro is available, it should also be considered.
|
2017-12-08 09:53:50 +13:00
|
|
|
|
|
|
|
#### Configuring your smartcard device
|
|
|
|
|
|
|
|
Your smartcard device should Just Work (TM) the moment you plug it into any
|
|
|
|
modern Linux or Mac workstation. You can verify it by running:
|
|
|
|
|
|
|
|
$ gpg --card-status
|
|
|
|
|
|
|
|
If you didn't get an error, but a full listing of the card details, then you
|
|
|
|
are good to go. Unfortunately, troubleshooting all possible reasons why things
|
|
|
|
may not be working for you is way beyond the scope of this guide. If you are
|
|
|
|
having trouble getting the card to work with GnuPG, please seek support via
|
|
|
|
your operating system's usual support channels.
|
|
|
|
|
|
|
|
##### PINs don't have to be numbers
|
|
|
|
|
|
|
|
Note, that despite having the name "PIN" (and implying that it must be a
|
|
|
|
"number"), neither the user PIN nor the admin PIN on the card need to be
|
|
|
|
numbers.
|
|
|
|
|
|
|
|
Your device will probably have default user and admin PINs set up when it
|
|
|
|
arrives. For Yubikeys, these are `123456` and `12345678` respectively. If
|
|
|
|
those don't work for you, please check any accompanying documentation
|
|
|
|
that came with your device.
|
|
|
|
|
|
|
|
##### Quick setup
|
|
|
|
|
|
|
|
To configure your smartcard, you will need to use the GnuPG menu system, as
|
|
|
|
there are no convenient command-line switches:
|
|
|
|
|
|
|
|
$ gpg --card-edit
|
2017-12-15 09:08:16 +13:00
|
|
|
[...omitted...]
|
2017-12-08 09:53:50 +13:00
|
|
|
gpg/card> admin
|
|
|
|
Admin commands are allowed
|
|
|
|
gpg/card> passwd
|
|
|
|
|
2019-04-08 19:49:49 +12:00
|
|
|
You should set the user PIN (1) and Admin PIN (3). Please make sure to record
|
|
|
|
and store these in a safe place -- especially the Admin PIN. You so rarely
|
|
|
|
need to use the Admin PIN, that you will inevitably forget what it is if
|
|
|
|
you do not record it.
|
2017-12-08 09:53:50 +13:00
|
|
|
|
|
|
|
Getting back to the main card menu, you can also set other values (such as
|
2018-01-24 04:50:52 +13:00
|
|
|
name, sex, login data, etc), but it's not necessary and will additionally leak
|
|
|
|
information about your smartcard should you lose it.
|
2017-12-08 09:53:50 +13:00
|
|
|
|
|
|
|
#### Moving the subkeys to your smartcard
|
|
|
|
|
|
|
|
Exit the card menu (using "q") and save all changes. Next, let's move your
|
2017-12-15 09:08:16 +13:00
|
|
|
subkeys onto the smartcard. You will need both your PGP key passphrase and the
|
2017-12-08 09:53:50 +13:00
|
|
|
admin PIN of the card for most operations. Remember, that `[fpr]` stands for
|
|
|
|
the full 40-character fingerprint of your key.
|
|
|
|
|
|
|
|
$ gpg --edit-key [fpr]
|
|
|
|
|
|
|
|
Secret subkeys are available.
|
|
|
|
|
|
|
|
pub rsa4096/AAAABBBBCCCCDDDD
|
2021-05-14 04:41:52 +12:00
|
|
|
created: 2021-05-01 expires: 2023-05-01 usage: C
|
2017-12-08 09:53:50 +13:00
|
|
|
trust: ultimate validity: ultimate
|
2021-05-14 04:41:52 +12:00
|
|
|
ssb cv25519/1111222233334444
|
|
|
|
created: 2021-05-01 expires: never usage: E
|
|
|
|
ssb ed25519/5555666677778888
|
|
|
|
created: 2021-05-01 expires: never usage: S
|
2017-12-08 09:53:50 +13:00
|
|
|
[ultimate] (1). Alice Engineer <alice@example.org>
|
|
|
|
[ultimate] (2) Alice Engineer <allie@example.net>
|
|
|
|
|
|
|
|
gpg>
|
|
|
|
|
|
|
|
Using `--edit-key` puts us into the menu mode again, and you will notice that
|
|
|
|
the key listing is a little different. From here on, all commands are done
|
|
|
|
from inside this menu mode, as indicated by `gpg>`.
|
|
|
|
|
|
|
|
First, let's select the key we'll be putting onto the card -- you do this by
|
|
|
|
typing `key 1` (it's the first one in the listing, our **[E]** subkey):
|
|
|
|
|
|
|
|
gpg> key 1
|
|
|
|
|
|
|
|
The output should be subtly different:
|
|
|
|
|
|
|
|
pub rsa4096/AAAABBBBCCCCDDDD
|
2021-05-14 04:41:52 +12:00
|
|
|
created: 2021-05-01 expires: 2023-05-01 usage: C
|
2017-12-08 09:53:50 +13:00
|
|
|
trust: ultimate validity: ultimate
|
2021-05-14 04:41:52 +12:00
|
|
|
ssb* cv25519/1111222233334444
|
|
|
|
created: 2021-05-01 expires: never usage: E
|
|
|
|
ssb ed25519/5555666677778888
|
|
|
|
created: 2021-05-01 expires: never usage: S
|
2017-12-08 09:53:50 +13:00
|
|
|
[ultimate] (1). Alice Engineer <alice@example.org>
|
|
|
|
[ultimate] (2) Alice Engineer <allie@example.net>
|
|
|
|
|
|
|
|
Notice the `*` that is next to the `ssb` line corresponding to the key -- it
|
2017-12-15 09:08:16 +13:00
|
|
|
indicates that the key is currently "selected." It works as a toggle, meaning
|
2017-12-08 09:53:50 +13:00
|
|
|
that if you type `key 1` again, the `*` will disappear and the key will not be
|
|
|
|
selected any more.
|
|
|
|
|
|
|
|
Now, let's move that key onto the smartcard:
|
|
|
|
|
|
|
|
gpg> keytocard
|
|
|
|
Please select where to store the key:
|
|
|
|
(2) Encryption key
|
|
|
|
Your selection? 2
|
|
|
|
|
|
|
|
Since it's our **[E]** key, it makes sense to put it into the Encryption slot.
|
2017-12-15 09:08:16 +13:00
|
|
|
When you submit your selection, you will be prompted first for your PGP key
|
2017-12-08 09:53:50 +13:00
|
|
|
passphrase, and then for the admin PIN. If the command returns without an
|
|
|
|
error, your key has been moved.
|
|
|
|
|
|
|
|
**Important**: Now type `key 1` again to unselect the first key, and `key 2`
|
|
|
|
to select the **[S]** key:
|
|
|
|
|
|
|
|
gpg> key 1
|
|
|
|
gpg> key 2
|
|
|
|
gpg> keytocard
|
|
|
|
Please select where to store the key:
|
|
|
|
(1) Signature key
|
|
|
|
(3) Authentication key
|
|
|
|
Your selection? 1
|
|
|
|
|
|
|
|
You can use the **[S]** key both for Signature and Authentication, but we want
|
|
|
|
to make sure it's in the Signature slot, so choose (1). Once again, if your
|
|
|
|
command returns without an error, then the operation was successful.
|
|
|
|
|
|
|
|
Finally, if you created an **[A]** key, you can move it to the card as well,
|
|
|
|
making sure first to unselect `key 2`. Once you're done, choose "q":
|
|
|
|
|
|
|
|
gpg> q
|
|
|
|
Save changes? (y/N) y
|
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
Saving the changes will delete the keys you moved to the card from your home
|
2017-12-08 09:53:50 +13:00
|
|
|
directory (but it's okay, because we have them in our backups should we need
|
|
|
|
to do this again for a replacement smartcard).
|
|
|
|
|
|
|
|
##### Verifying that the keys were moved
|
|
|
|
|
|
|
|
If you perform `--list-secret-keys` now, you will see a subtle difference in
|
|
|
|
the output:
|
|
|
|
|
|
|
|
$ gpg --list-secret-keys
|
2021-05-14 04:41:52 +12:00
|
|
|
sec# rsa4096 2021-05-01 [C] [expires: 2023-05-01]
|
2017-12-08 09:53:50 +13:00
|
|
|
111122223333444455556666AAAABBBBCCCCDDDD
|
|
|
|
uid [ultimate] Alice Engineer <alice@example.org>
|
|
|
|
uid [ultimate] Alice Engineer <allie@example.net>
|
2021-05-14 04:41:52 +12:00
|
|
|
ssb> cv25519 2021-05-01 [E]
|
|
|
|
ssb> ed25519 2021-05-01 [S]
|
2017-12-08 09:53:50 +13:00
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
The `>` in the `ssb>` output indicates that the subkey is only available on
|
|
|
|
the smartcard. If you go back into your secret keys directory and look at the
|
2017-12-08 09:53:50 +13:00
|
|
|
contents there, you will notice that the `.key` files there have been replaced
|
|
|
|
with stubs:
|
|
|
|
|
|
|
|
$ cd ~/.gnupg/private-keys-v1.d
|
|
|
|
$ strings *.key
|
|
|
|
|
|
|
|
The output should contain `shadowed-private-key` to indicate that these files
|
|
|
|
are only stubs and the actual content is on the smartcard.
|
|
|
|
|
|
|
|
#### Verifying that the smartcard is functioning
|
|
|
|
|
|
|
|
To verify that the smartcard is working as intended, you can create a
|
|
|
|
signature:
|
|
|
|
|
|
|
|
$ echo "Hello world" | gpg --clearsign > /tmp/test.asc
|
|
|
|
$ gpg --verify /tmp/test.asc
|
|
|
|
|
|
|
|
This should ask for your smartcard PIN on your first command, and then show
|
|
|
|
"Good signature" after you run `gpg --verify`.
|
|
|
|
|
|
|
|
Congratulations, you have successfully made it extremely difficult to steal
|
|
|
|
your digital developer identity!
|
|
|
|
|
2017-12-13 10:54:03 +13:00
|
|
|
### Other common GnuPG operations
|
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
Here is a quick reference for some common operations you'll need to do with
|
2017-12-13 10:54:03 +13:00
|
|
|
your PGP key.
|
|
|
|
|
|
|
|
In all of the below commands, the `[fpr]` is your key fingerprint.
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
#### Mounting your offline storage
|
2017-12-13 10:54:03 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
You will need your certification key for any of the operations below, so you
|
|
|
|
will first need to mount your backup offline storage and tell GnuPG to use it.
|
2017-12-13 10:54:03 +13:00
|
|
|
First, find out where the media got mounted, e.g. by looking at the output of
|
|
|
|
the `mount` command. Then, locate the directory with the backup of your GnuPG
|
|
|
|
directory and tell GnuPG to use that as its home:
|
|
|
|
|
2017-12-15 20:53:25 +13:00
|
|
|
$ export GNUPGHOME=/media/disk/name/gnupg-backup
|
2017-12-13 10:54:03 +13:00
|
|
|
$ gpg --list-secret-keys
|
|
|
|
|
|
|
|
You want to make sure that you see `sec` and not `sec#` in the output (the `#`
|
2017-12-15 09:08:16 +13:00
|
|
|
means the key is not available and you're still using your regular home
|
|
|
|
directory location).
|
2017-12-13 10:54:03 +13:00
|
|
|
|
|
|
|
##### Updating your regular GnuPG working directory
|
|
|
|
|
|
|
|
After you make any changes to your key using the offline storage, you will
|
|
|
|
want to import these changes back into your regular working directory:
|
|
|
|
|
2017-12-16 06:16:41 +13:00
|
|
|
$ gpg --export | gpg --homedir ~/.gnupg --import
|
2017-12-13 10:54:03 +13:00
|
|
|
$ unset GNUPGHOME
|
|
|
|
|
|
|
|
#### Extending key expiration date
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
The certification key we created has the default expiration date of 2 years
|
|
|
|
from the date of creation. This is done both for security reasons and to make
|
|
|
|
obsolete keys eventually disappear from keyservers.
|
2017-12-13 10:54:03 +13:00
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
To extend the expiration on your key by a year from current date, just run:
|
2017-12-13 10:54:03 +13:00
|
|
|
|
|
|
|
$ gpg --quick-set-expire [fpr] 1y
|
|
|
|
|
|
|
|
You can also use a specific date if that is easier to remember (e.g. your
|
2021-05-14 04:41:52 +12:00
|
|
|
birthday, January 1st, or Canada Day, 2030):
|
2017-12-13 10:54:03 +13:00
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
$ gpg --quick-set-expire [fpr] 2030-07-01
|
2017-12-13 10:54:03 +13:00
|
|
|
|
|
|
|
Remember to send the updated key back to keyservers:
|
|
|
|
|
|
|
|
$ gpg --send-key [fpr]
|
|
|
|
|
|
|
|
#### Revoking identities
|
|
|
|
|
|
|
|
If you need to revoke an identity (e.g. you changed employers and your old
|
|
|
|
email address is no longer valid), you can use a one-liner:
|
|
|
|
|
|
|
|
$ gpg --quick-revoke-uid [fpr] 'Alice Engineer <aengineer@example.net>'
|
|
|
|
|
|
|
|
You can also do the same with the menu mode using `gpg --edit-key [fpr]`.
|
|
|
|
|
|
|
|
Once you are done, remember to send the updated key back to keyservers:
|
|
|
|
|
|
|
|
$ gpg --send-key [fpr]
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
## Using PGP with Git
|
|
|
|
|
2018-01-19 10:32:31 +13:00
|
|
|
One of the core features of Git is its decentralized nature -- once a
|
|
|
|
repository is cloned to your system, you have full history of the project,
|
|
|
|
including all of its tags, commits and branches. However, with hundreds of
|
|
|
|
cloned repositories floating around, how does anyone verify that the
|
|
|
|
repository you downloaded has not been tampered with by a malicious third
|
|
|
|
party? You may have cloned it from GitHub or some other official-looking
|
2018-01-19 10:41:38 +13:00
|
|
|
location, but what if someone had managed to trick you?
|
2018-01-19 10:32:31 +13:00
|
|
|
|
|
|
|
Or what happens if a backdoor is discovered in one of the projects you've
|
|
|
|
worked on, and the "Author" line in the commit says it was done by you, while
|
2021-05-14 04:41:52 +12:00
|
|
|
you're pretty sure you had [nothing to do with it](https://github.com/jayphelps/git-blame-someone-else)?
|
2018-01-19 10:32:31 +13:00
|
|
|
|
2018-01-19 10:41:38 +13:00
|
|
|
To address both of these issues, Git introduced PGP integration. Signed tags
|
2018-01-19 10:32:31 +13:00
|
|
|
prove the repository integrity by assuring that its contents are exactly the
|
2018-01-19 10:41:38 +13:00
|
|
|
same as on the workstation of the developer who created the tag, while signed
|
2018-01-19 10:32:31 +13:00
|
|
|
commits make it nearly impossible for someone to impersonate you without
|
|
|
|
having access to your PGP keys.
|
|
|
|
|
2017-12-09 11:18:53 +13:00
|
|
|
### Checklist
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
- [ ] Understand signed tags, commits _(ESSENTIAL)_
|
2017-12-09 11:18:53 +13:00
|
|
|
- [ ] Configure git to use your key _(ESSENTIAL)_
|
|
|
|
- [ ] Learn how tag signing and verification works _(ESSENTIAL)_
|
|
|
|
- [ ] Configure git to always sign annotated tags _(NICE)_
|
|
|
|
- [ ] Learn how commit signing and verification works _(ESSENTIAL)_
|
|
|
|
- [ ] Configure git to always sign commits _(NICE)_
|
2017-12-13 10:54:03 +13:00
|
|
|
- [ ] Configure gpg-agent options _(ESSENTIAL)_
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
### Considerations
|
|
|
|
|
|
|
|
Git implements multiple levels of integration with PGP, first starting with
|
2021-05-14 04:41:52 +12:00
|
|
|
signed tags, and then introducing signed commits.
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
#### Understanding Git Hashes
|
|
|
|
|
|
|
|
Git is a complicated beast, but you need to know what a "hash" is in order to
|
|
|
|
have a good grasp on how PGP integrates with it. We'll narrow it down to two
|
|
|
|
kinds of hashes: tree hashes and commit hashes.
|
|
|
|
|
|
|
|
##### Tree hashes
|
|
|
|
|
2017-12-13 10:54:03 +13:00
|
|
|
Every time you commit a change to a repository, git records checksum hashes
|
2017-12-09 11:18:53 +13:00
|
|
|
of all objects in it -- contents (blobs), directories (trees), file names and
|
|
|
|
permissions, etc, for each subdirectory in the repository. It only does this
|
2017-12-13 10:54:03 +13:00
|
|
|
for trees and blobs that have changed with each commit, so as not to
|
|
|
|
re-checksum the entire tree unnecessarily if only a small part of it was
|
|
|
|
touched.
|
2017-12-09 11:18:53 +13:00
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
Then it calculates and stores the checksum of the toplevel tree, which will
|
|
|
|
inevitably be different if any part of the repository has changed.
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
##### Commit hashes
|
|
|
|
|
|
|
|
Once the tree hash has been created, git will calculate the commit hash, which
|
2017-12-15 09:08:16 +13:00
|
|
|
will include the following information about the repository and the change being
|
2017-12-09 11:18:53 +13:00
|
|
|
made:
|
|
|
|
|
|
|
|
- the checksum hash of the tree
|
|
|
|
- the checksum hash of the tree before the change (parent)
|
|
|
|
- information about the author (name, email, time of authorship)
|
|
|
|
- information about the committer (name, email, time of commit)
|
|
|
|
- the commit message
|
|
|
|
|
|
|
|
##### Hashing function
|
|
|
|
|
2017-12-13 10:54:03 +13:00
|
|
|
At the time of writing, git still uses the SHA1 hashing mechanism to calculate
|
2017-12-09 11:18:53 +13:00
|
|
|
checksums, though work is under way to transition to a stronger algorithm that
|
|
|
|
is more resistant to collisions. Note, that git already includes collision
|
|
|
|
avoidance routines, so it is believed that a successful collision attack
|
|
|
|
against git remains impractical.
|
|
|
|
|
|
|
|
#### Annotated tags and tag signatures
|
|
|
|
|
|
|
|
Git tags allow developers to mark specific commits in the history of each git
|
2017-12-13 10:54:03 +13:00
|
|
|
repository. Tags can be "lightweight" -- more or less just a pointer at a
|
|
|
|
specific commit, or they can be "annotated," which becomes its own object in
|
|
|
|
the git tree. An annotated tag object contains all of the following
|
|
|
|
information:
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
- the checksum hash of the commit being tagged
|
|
|
|
- the tag name
|
2017-12-13 10:54:03 +13:00
|
|
|
- information about the tagger (name, email, time of tagging)
|
2017-12-09 11:18:53 +13:00
|
|
|
- the tag message
|
|
|
|
|
2017-12-13 10:54:03 +13:00
|
|
|
A PGP-signed tag is simply an annotated tag with all these entries wrapped
|
2017-12-09 11:18:53 +13:00
|
|
|
around in a PGP signature. When a developer signs their git tag, they
|
|
|
|
effectively assure you of the following:
|
|
|
|
|
|
|
|
- who they are (and why you should trust them)
|
|
|
|
- what the state of their repository was at the time of signing:
|
|
|
|
- the tag includes the hash of the commit
|
|
|
|
- the commit hash includes the hash of the toplevel tree
|
2017-12-15 09:08:16 +13:00
|
|
|
- which includes hashes of all files, contents, and subtrees
|
2017-12-09 11:18:53 +13:00
|
|
|
- it also includes all information about authorship
|
|
|
|
- including exact times when changes were made
|
|
|
|
|
2017-12-13 10:54:03 +13:00
|
|
|
When you clone a git repository and verify a signed tag, that gives you
|
2017-12-15 09:08:16 +13:00
|
|
|
cryptographic assurance that _all contents in the repository, including all of
|
|
|
|
its history, are exactly the same as the contents of the repository on the
|
2017-12-13 10:54:03 +13:00
|
|
|
developer's computer at the time of signing_.
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
#### Signed commits
|
|
|
|
|
2017-12-13 10:54:03 +13:00
|
|
|
Signed commits are very similar to signed tags -- the contents of the commit
|
|
|
|
object are PGP-signed instead of the contents of the tag object. A commit
|
|
|
|
signature also gives you full verifiable information about the state of the
|
|
|
|
developer's tree at the time the signature was made. Tag signatures and commit
|
|
|
|
PGP signatures provide exact same security assurances about the repository and
|
|
|
|
its entire history.
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
#### Configure git to use your PGP key
|
|
|
|
|
|
|
|
If you only have one secret key in your keyring, then you don't really need to
|
|
|
|
do anything extra, as it becomes your default key.
|
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
However, if you happen to have multiple secret keys, you can tell git which
|
|
|
|
key should be used (`[fpr]` is the fingerprint of your key):
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
$ git config --global user.signingKey [fpr]
|
|
|
|
|
|
|
|
#### How to work with signed tags
|
|
|
|
|
|
|
|
To create a signed tag, simply pass the `-s` switch to the tag command:
|
|
|
|
|
|
|
|
$ git tag -s [tagname]
|
|
|
|
|
|
|
|
Our recommendation is to always sign git tags, as this allows other developers
|
|
|
|
to ensure that the git repository they are working with has not been
|
2017-12-15 09:08:16 +13:00
|
|
|
maliciously altered (e.g. in order to introduce backdoors).
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
##### How to verify signed tags
|
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
To verify a signed tag, simply use the `verify-tag` command:
|
2017-12-09 11:18:53 +13:00
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
$ git verify-tag [tagname]
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
If you are verifying someone else's git tag, then you will need to import
|
2017-12-13 10:54:03 +13:00
|
|
|
their PGP key. Please refer to the "Trusted Team communication" document in
|
|
|
|
the same repository for guidance on this topic.
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
##### Verifying at pull time
|
|
|
|
|
|
|
|
If you are pulling a tag from another fork of the project repository, git
|
|
|
|
should automatically verify the signature at the tip you're pulling and show
|
|
|
|
you the results during the merge operation:
|
|
|
|
|
|
|
|
$ git pull [url] tags/sometag
|
|
|
|
|
|
|
|
The merge message will contain something like this:
|
|
|
|
|
|
|
|
Merge tag 'sometag' of [url]
|
|
|
|
|
|
|
|
[Tag message]
|
|
|
|
|
|
|
|
# gpg: Signature made [...]
|
|
|
|
# gpg: Good signature from [...]
|
|
|
|
|
|
|
|
#### Configure git to always sign annotated tags
|
|
|
|
|
|
|
|
Chances are, if you're creating an annotated tag, you'll want to sign it. To
|
|
|
|
force git to always sign annotated tags, you can set a global configuration
|
|
|
|
option:
|
|
|
|
|
|
|
|
$ git config --global tag.forceSignAnnotated true
|
|
|
|
|
|
|
|
Alternatively, you can just train your muscle memory to always pass the `-s`
|
|
|
|
switch:
|
|
|
|
|
|
|
|
$ git tag -asm "Tag message" tagname
|
|
|
|
|
|
|
|
#### How to work with signed commits
|
|
|
|
|
|
|
|
It is easy to create signed commits, but it is much more difficult to
|
2017-12-13 10:54:03 +13:00
|
|
|
incorporate them into your workflow. Many projects use signed commits as a
|
|
|
|
sort of "Committed-by:" line equivalent that records code provenance -- the
|
|
|
|
signatures are rarely verified by others except when tracking down project
|
|
|
|
history. In a sense, signed commits are used for "tamper evidence," and not to
|
2017-12-15 09:08:16 +13:00
|
|
|
"tamper-proof" the git workflow.
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
To create a signed commit, you just need to pass the `-S` flag to the `git
|
2017-12-13 10:54:03 +13:00
|
|
|
commit` command (it's capital `-S` due to collision with another flag):
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
$ git commit -S
|
|
|
|
|
|
|
|
Our recommendation is to always sign commits and to require them of all
|
2017-12-13 10:54:03 +13:00
|
|
|
project members, regardless of whether anyone is verifying them (that can
|
|
|
|
always come at a later time).
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
##### How to verify signed commits
|
|
|
|
|
|
|
|
To verify a single commit you can use `verify-commit`:
|
|
|
|
|
|
|
|
$ git verify-commit [hash]
|
|
|
|
|
2017-12-13 10:54:03 +13:00
|
|
|
You can also look at repository logs and request that all commit signatures
|
2017-12-09 11:18:53 +13:00
|
|
|
are verified and shown:
|
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
$ git log --pretty=short --show-signature
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
##### Verifying commits during git merge
|
|
|
|
|
|
|
|
If all members of your project sign their commits, you can enforce signature
|
|
|
|
checking at merge time (and then sign the resulting merge commit itself using
|
|
|
|
the `-S` flag):
|
|
|
|
|
|
|
|
$ git merge --verify-signatures -S merged-branch
|
|
|
|
|
2017-12-13 10:54:03 +13:00
|
|
|
Note, that the merge will fail if there is even one commit that is not signed
|
|
|
|
or does not pass verification. As it is often the case, technology is the easy
|
|
|
|
part -- the human side of the equation is what makes adopting strict commit
|
2017-12-15 09:08:16 +13:00
|
|
|
signing for your project difficult.
|
2017-12-09 11:18:53 +13:00
|
|
|
|
|
|
|
##### If your project uses mailing lists for patch management
|
2017-12-08 09:53:50 +13:00
|
|
|
|
2017-12-09 11:18:53 +13:00
|
|
|
If your project uses a mailing list for submitting and processing patches,
|
|
|
|
then there is little use in signing commits, because all signature information
|
|
|
|
will be lost when sent through that medium. It is still useful to sign your
|
|
|
|
commits, just so others can refer to your publicly hosted git trees for
|
2017-12-13 10:54:03 +13:00
|
|
|
reference, but the upstream project receiving your patches will not be able to
|
|
|
|
verify them directly with git.
|
2017-12-08 09:53:50 +13:00
|
|
|
|
2017-12-09 11:18:53 +13:00
|
|
|
You can still sign the emails containing the patches, though.
|
2017-12-13 10:54:03 +13:00
|
|
|
|
|
|
|
#### Configure git to always sign commits
|
|
|
|
|
|
|
|
You can tell git to always sign commits:
|
|
|
|
|
|
|
|
git config --global commit.gpgSign true
|
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
Or you can train your muscle memory to always pass the `-S` flag to all `git
|
|
|
|
commit` operations (this includes `--amend`).
|
2017-12-13 10:54:03 +13:00
|
|
|
|
|
|
|
#### Configure gpg-agent options
|
|
|
|
|
|
|
|
The GnuPG agent is a helper tool that will start automatically whenever you
|
2017-12-15 09:08:16 +13:00
|
|
|
use the `gpg` command and run in the background with the purpose of caching
|
2017-12-13 10:54:03 +13:00
|
|
|
the private key passphrase. This way you only have to unlock your key once to
|
|
|
|
use it repeatedly (very handy if you need to sign a bunch of git operations in
|
|
|
|
an automated script without having to continuously retype your passphrase).
|
|
|
|
|
|
|
|
There are two options you should know in order to tweak when the passphrase
|
|
|
|
should be expired from cache:
|
|
|
|
|
|
|
|
- `default-cache-ttl` (seconds): If you use the same key again before the
|
|
|
|
time-to-live expires, the countdown will reset for another period.
|
|
|
|
The default is 600 (10 minutes).
|
|
|
|
- `max-cache-ttl` (seconds): Regardless of how recently you've used the key
|
|
|
|
since initial passphrase entry, if the maximum time-to-live countdown
|
|
|
|
expires, you'll have to enter the passphrase again. The default is 30
|
|
|
|
minutes.
|
|
|
|
|
|
|
|
If you find either of these defaults too short (or too long), you can edit
|
|
|
|
your `~/.gnupg/gpg-agent.conf` file to set your own values:
|
|
|
|
|
|
|
|
# set to 30 minutes for regular ttl, and 2 hours for max ttl
|
|
|
|
default-cache-ttl 1800
|
|
|
|
max-cache-ttl 7200
|
|
|
|
|
|
|
|
##### Bonus: Using gpg-agent with ssh
|
|
|
|
|
|
|
|
If you've created an **[A]** (Authentication) key and moved it to the
|
|
|
|
smartcard, you can use it with ssh for adding 2-factor authentication for your
|
|
|
|
ssh sessions. You just need to tell your environment to use the correct socket
|
|
|
|
file for talking to the agent.
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
All you need is add this to your `.bashrc`:
|
2017-12-13 10:54:03 +13:00
|
|
|
|
|
|
|
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
|
|
|
|
|
2021-05-14 04:41:52 +12:00
|
|
|
Then start a new login session for the changes to take effect:
|
2017-12-13 10:54:03 +13:00
|
|
|
|
|
|
|
$ bash
|
|
|
|
$ ssh-add -L
|
|
|
|
|
|
|
|
The last command should list the SSH representation of your PGP Auth key (the
|
2017-12-15 09:08:16 +13:00
|
|
|
comment should say `cardno:XXXXXXXX` at the end to indicate it's coming from
|
2017-12-13 10:54:03 +13:00
|
|
|
the smartcard).
|
|
|
|
|
2017-12-15 09:08:16 +13:00
|
|
|
To enable key-based logins with ssh, just add the `ssh-add -L` output to
|
2017-12-13 10:54:03 +13:00
|
|
|
`~/.ssh/authorized_keys` on remote systems you log in to. Congratulations,
|
|
|
|
you've just made your ssh credentials extremely difficult to steal.
|
|
|
|
|
|
|
|
As a bonus, you can get other people's PGP-based ssh keys from public
|
2017-12-15 09:08:16 +13:00
|
|
|
keyservers, should you need to grant them ssh access to anything:
|
2017-12-13 10:54:03 +13:00
|
|
|
|
|
|
|
$ gpg --export-ssh-key [keyid]
|
|
|
|
|
|
|
|
This can come in super handy if you need to allow developers access to git
|
|
|
|
repositories over ssh.
|
|
|
|
|
2017-12-14 10:16:44 +13:00
|
|
|
## Protecting online accounts
|
|
|
|
|
|
|
|
### Checklist
|
|
|
|
|
|
|
|
- [ ] Get a U2F-capable device _(ESSENTIAL)_
|
|
|
|
- [ ] Enable 2-factor authentication for your online accounts _(ESSENTIAL)_
|
|
|
|
- [ ] GitHub/GitLab
|
|
|
|
- [ ] Google
|
|
|
|
- [ ] Social Media
|
|
|
|
- [ ] Use U2F as primary mechanism, with TOTP as fallback _(ESSENTIAL)_
|
|
|
|
|
|
|
|
### Considerations
|
|
|
|
|
|
|
|
You may have noticed how a lot of your online developer identity is tied to
|
|
|
|
your email address. If someone can gain access to your mailbox, they would be
|
|
|
|
able to do a lot of damage to you personally, and to your reputation as a free
|
|
|
|
software developer. Protecting your email accounts is just as important as
|
|
|
|
protecting your PGP keys.
|
|
|
|
|
|
|
|
#### Two-factor authentication with Fido U2F
|
|
|
|
|
2017-12-14 10:37:41 +13:00
|
|
|
[Two-factor authentication](https://en.wikipedia.org/wiki/Multi-factor_authentication)
|
|
|
|
is a mechanism to improve account security by requiring a physical token in
|
2017-12-14 10:16:44 +13:00
|
|
|
addition to a username and password. The goal is to make sure that even if
|
|
|
|
someone steals your password (via keylogging, shoulder surfing, or other
|
|
|
|
means), they still wouldn't be able to gain access to your account without
|
2017-12-14 10:37:41 +13:00
|
|
|
having in their possession a specific physical device ("something you have"
|
|
|
|
factor).
|
2017-12-14 10:16:44 +13:00
|
|
|
|
|
|
|
The most widely known mechanisms for 2-factor authentication are:
|
|
|
|
|
|
|
|
- SMS-based verification
|
2017-12-14 10:37:41 +13:00
|
|
|
- Time-based One-Time Passwords (TOTP) via a smartphone app, such as
|
|
|
|
the "Google Authenticator" or similar solutions
|
2017-12-14 10:16:44 +13:00
|
|
|
- Hardware tokens supporting Fido U2F
|
|
|
|
|
|
|
|
SMS-based verification is easiest to configure, but has the following
|
2017-12-14 10:37:41 +13:00
|
|
|
important downsides: it is useless in areas without signal (e.g. most building
|
2017-12-14 10:16:44 +13:00
|
|
|
basements), and can be defeated if the attacker is able to intercept or divert
|
2017-12-15 09:08:16 +13:00
|
|
|
SMS messages, for example by cloning your SIM card.
|
2017-12-14 10:16:44 +13:00
|
|
|
|
|
|
|
TOTP-based multi-factor authentication offers more protection than SMS, but
|
2017-12-14 10:37:41 +13:00
|
|
|
has important scaling downsides (there are only so many tokens you can add to
|
2017-12-15 09:08:16 +13:00
|
|
|
your smartphone app before finding the correct one becomes unwieldy). Plus,
|
2017-12-14 10:16:44 +13:00
|
|
|
there's no avoiding the fact that your secret key ends up stored on the
|
2017-12-14 10:37:41 +13:00
|
|
|
smartphone itself -- which is a complex, globally connected device that may or
|
|
|
|
may not have been receiving timely security patches from the manufacturer.
|
2017-12-14 10:16:44 +13:00
|
|
|
|
|
|
|
Most importantly, neither TOTP nor SMS methods protect you from phishing
|
2017-12-15 09:08:16 +13:00
|
|
|
attacks -- if the phisher is able to steal both your account password and the
|
|
|
|
2-factor token, they can replay them on the legitimate site and gain access to
|
|
|
|
your account.
|
2017-12-14 10:16:44 +13:00
|
|
|
|
|
|
|
[Fido U2F](https://en.wikipedia.org/wiki/Universal_2nd_Factor) is a standard
|
|
|
|
developed specifically to provide a mechanism for 2-factor authentication
|
2017-12-14 10:37:41 +13:00
|
|
|
*and* to combat credential phishing. The U2F protocol will store each site's
|
|
|
|
unique key on the USB token and will prevent you from accidentally giving the
|
|
|
|
attacker both your password and your one-time token if you try to use it on
|
|
|
|
anything other than the legitimate website.
|
2017-12-14 10:16:44 +13:00
|
|
|
|
|
|
|
Both Chrome and Firefox support U2F 2-factor authentication, and hopefully
|
|
|
|
other browsers will soon follow.
|
|
|
|
|
|
|
|
#### Get a token capable of Fido U2F
|
|
|
|
|
|
|
|
There are [many options available](http://www.dongleauth.info/dongles/) for
|
|
|
|
hardware tokens with Fido U2F support, but if you're already ordering a
|
2017-12-14 10:37:41 +13:00
|
|
|
smartcard-capable physical device, then your best option is a Yubikey 4, which
|
2017-12-14 10:16:44 +13:00
|
|
|
supports both.
|
|
|
|
|
|
|
|
#### Enable 2-factor authentication on your online accounts
|
|
|
|
|
|
|
|
You definitely want to enable this option on the email provider you are using
|
|
|
|
(especially if it is Google, which has excellent support for U2F). Other sites
|
2017-12-14 10:37:41 +13:00
|
|
|
where this functionality should be enabled are:
|
|
|
|
|
|
|
|
- **GitHub**: it probably occurred to you when you uploaded your PGP public key
|
|
|
|
that if anyone else is able to gain access to your account, they can replace
|
|
|
|
your key with their own. If you publish code on GitHub, you should take care
|
|
|
|
of your account security by protecting it with U2F-backed authentication.
|
|
|
|
- **GitLab**: for the same reasons as above.
|
|
|
|
- **Google**: if you have a google account, you will be surprised how many
|
|
|
|
sites allow logging in with Google authentication instead of site-specific
|
2017-12-14 10:16:44 +13:00
|
|
|
credentials.
|
2017-12-14 10:37:41 +13:00
|
|
|
- **Facebook**: same as above, a lot of online sites offer the option to
|
|
|
|
authenticate using a Facebook account. You should 2-factor protect your
|
|
|
|
Facebook account even if you do not use it.
|
2017-12-14 10:16:44 +13:00
|
|
|
- Other sites, as you deem necessary. See
|
|
|
|
[dongleauth.info](http://www.dongleauth.info) for inspiration.
|
|
|
|
|
|
|
|
#### Configure TOTP failover, if possible
|
|
|
|
|
|
|
|
Many sites will allow you to configure multiple 2-factor mechanisms, and the
|
2017-12-15 09:08:16 +13:00
|
|
|
recommended setup is:
|
2017-12-14 10:16:44 +13:00
|
|
|
|
|
|
|
- U2F token as the primary mechanism
|
|
|
|
- TOTP phone app as the secondary mechanism
|
|
|
|
|
2017-12-14 10:37:41 +13:00
|
|
|
This way, even if you lose your U2F token, you should be able to re-gain
|
|
|
|
access to your account. Alternatively, you can enroll multiple U2F tokens
|
|
|
|
(e.g. you can get another cheap token that only does U2F and use it for
|
|
|
|
backup reasons).
|
2017-12-13 10:54:03 +13:00
|
|
|
|
|
|
|
## Further reading
|
|
|
|
|
|
|
|
By this point you have accomplished the following important tasks:
|
|
|
|
|
|
|
|
1. Created your developer identity and protected it using PGP cryptography.
|
|
|
|
2. Configured your environment so your identity is not easily stolen by moving
|
2021-05-14 04:41:52 +12:00
|
|
|
your certification key offline and your subkeys to an external hardware
|
|
|
|
device.
|
2017-12-13 10:54:03 +13:00
|
|
|
3. Configured your git environment to ensure that anyone using your project is
|
|
|
|
able to verify the integrity of the repository and its entire history.
|
2017-12-14 10:37:41 +13:00
|
|
|
4. Secured your online accounts using 2-factor authentication.
|
2017-12-13 10:54:03 +13:00
|
|
|
|
|
|
|
You are already in a good place, but you should also read up on the following
|
|
|
|
topics:
|
|
|
|
|
|
|
|
- How to secure your team communication (see the document in this repository).
|
|
|
|
Decisions regarding your project development and governance require just as
|
|
|
|
much careful protection as any committed code, if not so. Make sure that
|
|
|
|
your team communication is trusted and the integrity of all decisions is
|
|
|
|
verified.
|
|
|
|
- How to secure your workstation (see the document in this repository). Your
|
|
|
|
goal is to minimize risky behaviour that would cause your project code to be
|
|
|
|
contaminated, or your developer identity to be stolen.
|
|
|
|
- How to write secure code (see various documentation related to the
|
|
|
|
programming languages and libraries used by your project). Bad, insecure
|
|
|
|
code is still bad, insecure code even if there is a PGP signature on the
|
|
|
|
commit that introduced it.
|