Merge branch 'master' of https://github.com/mricon/itpol into mricon-master
Signed-off-by: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
This commit is contained in:
commit
e536c34df0
|
@ -1,984 +0,0 @@
|
||||||
# Kernel developer PGP guide
|
|
||||||
|
|
||||||
Updated: 2018-01-24
|
|
||||||
|
|
||||||
*Status: CURRENT, BETA*
|
|
||||||
|
|
||||||
### Table of contents
|
|
||||||
|
|
||||||
- [Kernel developer PGP guide](#kernel-developer-pgp-guide)
|
|
||||||
- [Table of contents](#table-of-contents)
|
|
||||||
- [Target audience](#target-audience)
|
|
||||||
- [Structure](#structure)
|
|
||||||
- [Checklist priority levels](#checklist-priority-levels)
|
|
||||||
- [The role of PGP in Linux Kernel development](#the-role-of-pgp-in-linux-kernel-development)
|
|
||||||
- [Trusting the developers, not infrastructure](#trusting-the-developers-not-infrastructure)
|
|
||||||
- [PGP tools](#pgp-tools)
|
|
||||||
- [Checklist](#checklist)
|
|
||||||
- [Considerations](#considerations)
|
|
||||||
- [Installing GnuPG](#installing-gnupg)
|
|
||||||
- [Making sure you always use GnuPG v.2](#making-sure-you-always-use-gnupg-v2)
|
|
||||||
- [Configure gpg-agent options](#configure-gpg-agent-options)
|
|
||||||
- [Set up a refresh cronjob](#set-up-a-refresh-cronjob)
|
|
||||||
- [Protecting your master PGP key](#protecting-your-master-pgp-key)
|
|
||||||
- [Checklist](#checklist-1)
|
|
||||||
- [Considerations](#considerations-1)
|
|
||||||
- [Understanding the "Master" (Certify) key](#understanding-the-%22master%22-certify-key)
|
|
||||||
- [Ensure your passphrase is strong](#ensure-your-passphrase-is-strong)
|
|
||||||
- [Create a separate Signing subkey](#create-a-separate-signing-subkey)
|
|
||||||
- [RSA vs. ECC subkeys](#rsa-vs-ecc-subkeys)
|
|
||||||
- [Back up your master key for disaster recovery](#back-up-your-master-key-for-disaster-recovery)
|
|
||||||
- [Back up your whole GnuPG directory](#back-up-your-whole-gnupg-directory)
|
|
||||||
- [Prepare detachable encrypted storage](#prepare-detachable-encrypted-storage)
|
|
||||||
- [Back up your GnuPG directory](#back-up-your-gnupg-directory)
|
|
||||||
- [Remove the master key from your homedir](#remove-the-master-key-from-your-homedir)
|
|
||||||
- [Removing your master key](#removing-your-master-key)
|
|
||||||
- [If you don't have the "private-keys-v1.d" directory](#if-you-dont-have-the-%22private-keys-v1d%22-directory)
|
|
||||||
- [Move the subkeys to a dedicated crypto device](#move-the-subkeys-to-a-dedicated-crypto-device)
|
|
||||||
- [Checklist](#checklist-2)
|
|
||||||
- [Considerations](#considerations-2)
|
|
||||||
- [The benefits of smartcards](#the-benefits-of-smartcards)
|
|
||||||
- [Available smartcard devices](#available-smartcard-devices)
|
|
||||||
- [Configuring your smartcard device](#configuring-your-smartcard-device)
|
|
||||||
- [Quick setup](#quick-setup)
|
|
||||||
- [PINs don't have to be numbers](#pins-dont-have-to-be-numbers)
|
|
||||||
- [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)
|
|
||||||
- [Mounting your master key offline storage](#mounting-your-master-key-offline-storage)
|
|
||||||
- [Updating your regular GnuPG working directory](#updating-your-regular-gnupg-working-directory)
|
|
||||||
- [Extending key expiration date](#extending-key-expiration-date)
|
|
||||||
- [Using PGP with Git](#using-pgp-with-git)
|
|
||||||
- [Checklist](#checklist-3)
|
|
||||||
- [Considerations](#considerations-3)
|
|
||||||
- [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)
|
|
||||||
- [Creating signed commits](#creating-signed-commits)
|
|
||||||
- [Configure git to always sign commits](#configure-git-to-always-sign-commits)
|
|
||||||
- [How to verify kernel developer identities](#how-to-verify-kernel-developer-identities)
|
|
||||||
- [Checklist](#checklist-4)
|
|
||||||
- [Considerations](#considerations-4)
|
|
||||||
- [Configure auto-key-retrieval using WKD and DANE](#configure-auto-key-retrieval-using-wkd-and-dane)
|
|
||||||
- [Web of Trust (WOT) vs. Trust on First Use (TOFU)](#web-of-trust-wot-vs-trust-on-first-use-tofu)
|
|
||||||
- [Learn to use keyservers (more) safely](#learn-to-use-keyservers-more-safely)
|
|
||||||
|
|
||||||
### Target audience
|
|
||||||
|
|
||||||
This document is aimed at Linux kernel developers, and especially subsystem
|
|
||||||
maintainers. It contains a subset of information discussed in the more
|
|
||||||
general "Protecting Code Integrity" guide found in the same repository. If you
|
|
||||||
are not a Linux kernel developer, you should read the more general guide
|
|
||||||
instead.
|
|
||||||
|
|
||||||
This document covers the following topics:
|
|
||||||
|
|
||||||
1. How to improve your PGP key security
|
|
||||||
2. When and how to use PGP with git
|
|
||||||
3. How to verify fellow kernel developer identities
|
|
||||||
|
|
||||||
### Structure
|
|
||||||
|
|
||||||
Each section is split into two areas:
|
|
||||||
|
|
||||||
- A checklist of actionable items
|
|
||||||
- Free-form list of considerations that explain what dictated these decisions,
|
|
||||||
together with configuration instructions
|
|
||||||
|
|
||||||
#### 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.
|
|
||||||
- _(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 commitment to security, you should adjust them as you see fit.
|
|
||||||
|
|
||||||
## The role of PGP in Linux Kernel development
|
|
||||||
|
|
||||||
PGP helps ensure the integrity of the code that is produced by the Linux
|
|
||||||
Kernel development community and, to a lesser degree, establish trusted
|
|
||||||
communication channels between developers via PGP-signed email exchange.
|
|
||||||
|
|
||||||
The Linux Kernel source code is available in two main formats:
|
|
||||||
|
|
||||||
- Distributed source repositories (git)
|
|
||||||
- Periodic release snapshots (tarballs)
|
|
||||||
|
|
||||||
Both git repositories and tarballs carry PGP signatures of the kernel
|
|
||||||
developers who create official kernel releases. These signatures offer a
|
|
||||||
cryptographic guarantee that downloadable versions made available via
|
|
||||||
kernel.org or any other mirrors are identical to what these developers have on
|
|
||||||
their workstations. To this end:
|
|
||||||
|
|
||||||
- git repositories provide PGP signatures on all tags
|
|
||||||
- tarballs provide detached PGP signatures with all downloads
|
|
||||||
|
|
||||||
### Trusting the developers, not infrastructure
|
|
||||||
|
|
||||||
Ever since the 2011 compromise of core kernel.org systems, the main operating
|
|
||||||
principle of the Kernel Archives project has been to assume that any part of
|
|
||||||
the infrastructure can be compromised at any time. For this reason, the
|
|
||||||
administrators have taken deliberate steps to emphasize that trust must always
|
|
||||||
be placed with developers and never with the code hosting infrastructure,
|
|
||||||
regardless of how good the security practices for the latter may be.
|
|
||||||
|
|
||||||
The above guiding principle is the reason why this guide is needed. We want to
|
|
||||||
make sure that by placing trust into developers we do not simply shift the
|
|
||||||
blame for potential future security incidents to someone else. The goal is to
|
|
||||||
provide a set of guidelines developers can use to create a secure working
|
|
||||||
environment and safeguard the PGP keys used to establish the integrity of the
|
|
||||||
Linux Kernel itself.
|
|
||||||
|
|
||||||
## PGP tools
|
|
||||||
|
|
||||||
### Checklist
|
|
||||||
|
|
||||||
- [ ] Make sure you use GnuPG version 2 _(ESSENTIAL)_
|
|
||||||
- [ ] Configure gpg-agent _(ESSENTIAL)_
|
|
||||||
- [ ] Set up a refresh cronjob _(ESSENTIAL)_
|
|
||||||
|
|
||||||
### Considerations
|
|
||||||
|
|
||||||
### Installing GnuPG
|
|
||||||
|
|
||||||
Your distro should already have GnuPG installed by default, you just need to
|
|
||||||
verify that you are using version 2.x and not the legacy 1.4 release --
|
|
||||||
many distributions still package both, with the default `gpg` command invoking
|
|
||||||
GnuPG v.1. To check, run:
|
|
||||||
|
|
||||||
$ gpg --version | head -n1
|
|
||||||
|
|
||||||
If you see `gpg (GnuPG) 1.4.x`, then you are using GnuPG v.1. Try the `gpg2`
|
|
||||||
command (if you don't have it, you may need to install the gnupg2 package):
|
|
||||||
|
|
||||||
$ gpg2 --version | head -n1
|
|
||||||
|
|
||||||
If you see `gpg (GnuPG) 2.x.x`, then you are good to go. This guide will
|
|
||||||
assume you have the version 2.2 of GnuPG (or later). If you are using version
|
|
||||||
2.0 of GnuPG, then some of the commands in this guide will not work, and you
|
|
||||||
should consider installing the latest 2.2 version of GnuPG. Versions of
|
|
||||||
gnupg-2.1.11 and later should be compatible for the purposes of this guide as
|
|
||||||
well.
|
|
||||||
|
|
||||||
##### Making sure you always use GnuPG v.2
|
|
||||||
|
|
||||||
If you have both `gpg` and `gpg2` commands, you should make sure you are
|
|
||||||
always using GnuPG v2, not the legacy version. You can enforce this by setting
|
|
||||||
the appropriate alias:
|
|
||||||
|
|
||||||
$ alias gpg=gpg2
|
|
||||||
|
|
||||||
You can put that in your `.bashrc` to make sure it's always the case.
|
|
||||||
|
|
||||||
#### Configure gpg-agent options
|
|
||||||
|
|
||||||
The GnuPG agent is a helper tool that will start automatically whenever you
|
|
||||||
use the `gpg` command and run in the background with the purpose of caching
|
|
||||||
the private key passphrase. It is no longer necessary to start it manually
|
|
||||||
at the beginning of your shell session.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
#### Set up a refresh cronjob
|
|
||||||
|
|
||||||
You will need to regularly refresh your keyring in order to get the latest
|
|
||||||
changes on other people's public keys, which is best done with a daily
|
|
||||||
cronjob:
|
|
||||||
|
|
||||||
$ crontab -e
|
|
||||||
|
|
||||||
Add the following on a new line:
|
|
||||||
|
|
||||||
@daily /usr/bin/gpg2 --refresh >/dev/null 2>&1
|
|
||||||
|
|
||||||
**NOTE**: check the full path to your `gpg` or `gpg2` command and use the `gpg2`
|
|
||||||
command if regular `gpg` for you is the legacy GnuPG v.1.
|
|
||||||
|
|
||||||
## Protecting your master PGP key
|
|
||||||
|
|
||||||
### Checklist
|
|
||||||
|
|
||||||
- [ ] Understand the "master" key vs. subkeys _(ESSENTIAL)_
|
|
||||||
- [ ] Ensure your private key passphrase is strong _(ESSENTIAL)_
|
|
||||||
- [ ] Create a separate **[S]** subkey _(ESSENTIAL)_
|
|
||||||
- [ ] Back up the master key using paperkey _(ESSENTIAL)_
|
|
||||||
- [ ] Back up your whole `.gnupg` directory to encrypted media _(ESSENTIAL)_
|
|
||||||
- [ ] Remove the master key from your homedir _(ESSENTIAL)_
|
|
||||||
|
|
||||||
### Considerations
|
|
||||||
|
|
||||||
This guide assumes that you already have a PGP key that you use for Linux
|
|
||||||
Kernel development purposes. If you do not yet have one, please see the
|
|
||||||
"Protecting Code Integrity" document in this repository for guidance on how to
|
|
||||||
create a new one.
|
|
||||||
|
|
||||||
You should also make a new key if your current one is weaker than 2048 bits
|
|
||||||
(RSA).
|
|
||||||
|
|
||||||
#### Understanding the "Master" (Certify) key
|
|
||||||
|
|
||||||
In this and next section we'll talk about the "master key" and "subkeys". It
|
|
||||||
is important to understand the following:
|
|
||||||
|
|
||||||
1. There are no technical differences between the "master key" and "subkeys."
|
|
||||||
2. At creation time, we assign functional limitations to each key by
|
|
||||||
giving it specific capabilities.
|
|
||||||
3. A PGP key can have 4 capabilities.
|
|
||||||
- **[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
|
|
||||||
4. A single key may have multiple capabilities.
|
|
||||||
|
|
||||||
The key carrying the **[C]** (certify) capability is considered the "master"
|
|
||||||
key because it is the only key that can be used to indicate relationship with
|
|
||||||
other keys. Only the **[C]** key can be used to:
|
|
||||||
|
|
||||||
- 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
|
|
||||||
|
|
||||||
By default, GnuPG creates the following when generating new keys:
|
|
||||||
|
|
||||||
- A master key carrying both Certify and Sign capabilities (**[SC]**)
|
|
||||||
- A separate subkey with the Encryption capability (**[E]**)
|
|
||||||
|
|
||||||
If you used the default parameters when generating your key, then that is what
|
|
||||||
you will have. You can verify by running `gpg --list-secret-keys`, for
|
|
||||||
example:
|
|
||||||
|
|
||||||
sec rsa2048 2018-01-23 [SC] [expires: 2020-01-23]
|
|
||||||
000000000000000000000000AAAABBBBCCCCDDDD
|
|
||||||
uid [ultimate] Alice Dev <adev@kernel.org>
|
|
||||||
ssb rsa2048 2018-01-23 [E] [expires: 2020-01-23]
|
|
||||||
|
|
||||||
Any key carrying the **[C]** capability is your master key, regardless of any
|
|
||||||
other capabilities it may have assigned to it.
|
|
||||||
|
|
||||||
The long line under the `sec` entry is your key fingerprint -- whenever you
|
|
||||||
see `[fpr]` in the examples below, that 40-character string is what it refers
|
|
||||||
to.
|
|
||||||
|
|
||||||
#### Ensure your passphrase is strong
|
|
||||||
|
|
||||||
GnuPG uses passphrases to encrypt your private keys before storing them on
|
|
||||||
disk. This way, even if your `.gnupg` directory is leaked or stolen in its
|
|
||||||
entirety, the attackers cannot use your private keys without first obtaining
|
|
||||||
the passphrase to decrypt them.
|
|
||||||
|
|
||||||
It is absolutely essential that your private keys are protected by a
|
|
||||||
strong passphrase. To set it or change it, use:
|
|
||||||
|
|
||||||
$ gpg --change-passphrase [fpr]
|
|
||||||
|
|
||||||
#### Create a separate Signing subkey
|
|
||||||
|
|
||||||
Our goal is to protect your master key by moving it to offline media, so
|
|
||||||
if you only have a combined **[SC]** key, then you should create a separate
|
|
||||||
signing subkey.
|
|
||||||
|
|
||||||
##### RSA vs. ECC subkeys
|
|
||||||
|
|
||||||
GnuPG 2.1 and later has full support for Elliptic Curve Cryptography, with
|
|
||||||
ability to combine ECC subkeys with traditional RSA master keys. The main
|
|
||||||
upside of ECC cryptography is that it is much faster computationally and
|
|
||||||
creates much smaller signatures when compared byte for byte with 2048+ bit RSA
|
|
||||||
keys.
|
|
||||||
|
|
||||||
Unless you plan on using a smartcard device that does not support ECC
|
|
||||||
operations, we recommend that you create an ECC signing subkey for your kernel
|
|
||||||
work:
|
|
||||||
|
|
||||||
$ gpg --quick-add-key [fpr] ed25519 sign
|
|
||||||
|
|
||||||
If for some reason you prefer to stay with RSA subkeys, just replace "ed25519"
|
|
||||||
with "rsa2048" in the above command.
|
|
||||||
|
|
||||||
Remember to tell the keyservers about this change, so others can pull down
|
|
||||||
your new subkey:
|
|
||||||
|
|
||||||
$ gpg --send-key [fpr]
|
|
||||||
|
|
||||||
#### Back up your master key for disaster recovery
|
|
||||||
|
|
||||||
The more signatures you have on your PGP key from other developers, the more
|
|
||||||
reasons you have to create a backup version that lives on something other than
|
|
||||||
digital media, for disaster recovery reasons.
|
|
||||||
|
|
||||||
The best way to create a printable hardcopy of your private key is by using
|
|
||||||
the `paperkey` software written for this very purpose. See `man paperkey` for
|
|
||||||
more details on the output format and its benefits over other solutions.
|
|
||||||
Paperkey should already be packaged for most distributions.
|
|
||||||
|
|
||||||
Run the following command to create a hardcopy backup of your private key:
|
|
||||||
|
|
||||||
$ gpg --export-secret-key [fpr] | paperkey -o /tmp/key-backup.txt
|
|
||||||
|
|
||||||
Print out that file (or pipe the output straight to lpr), then take a pen and
|
|
||||||
write your passphrase on the margin of the paper. **This is strongly
|
|
||||||
recommended** because the key printout is still encrypted with that
|
|
||||||
passphrase, and if you ever change it you will not remember what it used to be
|
|
||||||
when you had created the backup -- *guaranteed*.
|
|
||||||
|
|
||||||
Put the resulting printout and the hand-written passphrase into an envelope
|
|
||||||
and store in a secure and well-protected place, preferably away from your
|
|
||||||
home, such as your bank vault.
|
|
||||||
|
|
||||||
**NOTE ON PRINTERS**: Your printer is probably no longer a simple dumb device
|
|
||||||
connected to your parallel port, but since the output is still encrypted with
|
|
||||||
your passphrase, printing out even to "cloud-integrated" modern printers
|
|
||||||
should remain a relatively safe operation. One option is to change the
|
|
||||||
passphrase on your master key immediately after you are done with paperkey.
|
|
||||||
|
|
||||||
#### Back up your whole GnuPG directory
|
|
||||||
|
|
||||||
**!!!Do not skip this step!!!**
|
|
||||||
|
|
||||||
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`). You will also rely on these external copies whenever
|
|
||||||
you need to use your Certify key -- such as when making changes to your own
|
|
||||||
key or signing other people's keys after conferences and meetups.
|
|
||||||
|
|
||||||
##### Prepare detachable encrypted storage
|
|
||||||
|
|
||||||
Start by getting a small USB "thumb" drive (preferably two!) that you will use
|
|
||||||
for backup purposes. You will need to encrypt them before using them for our
|
|
||||||
purposes:
|
|
||||||
|
|
||||||
- [Ubuntu instructions](https://help.ubuntu.com/community/EncryptedFilesystemsOnRemovableStorage)
|
|
||||||
|
|
||||||
For the encryption passphrase, you can use the same one as on your master key.
|
|
||||||
|
|
||||||
##### 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`).
|
|
||||||
|
|
||||||
Once you know the full mount path, copy your entire GnuPG directory there:
|
|
||||||
|
|
||||||
$ cp -a ~/.gnupg [/media/disk/name]/gnupg-backup
|
|
||||||
|
|
||||||
(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:
|
|
||||||
|
|
||||||
$ gpg --homedir=[/media/disk/name]/gnupg-backup --list-key [fpr]
|
|
||||||
|
|
||||||
If you don't get any errors, then you should be good to go. Unmount the USB
|
|
||||||
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
|
|
||||||
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.
|
|
||||||
|
|
||||||
#### Remove the master key from your homedir
|
|
||||||
|
|
||||||
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
|
|
||||||
recommended setup is to remove your master key from your home directory and
|
|
||||||
store it on offline storage.
|
|
||||||
|
|
||||||
##### Removing your master key
|
|
||||||
|
|
||||||
Please see the previous section and make sure you have backed up your GnuPG
|
|
||||||
directory in its entirety. What we are about to do will render your key
|
|
||||||
useless if you do not have a usable backup!
|
|
||||||
|
|
||||||
First, identify the keygrip of your master key:
|
|
||||||
|
|
||||||
$ gpg --with-keygrip --list-key [fpr]
|
|
||||||
|
|
||||||
The output will be something like this:
|
|
||||||
|
|
||||||
pub rsa2048 2018-01-24 [SC] [expires: 2020-01-24]
|
|
||||||
000000000000000000000000AAAABBBBCCCCDDDD
|
|
||||||
Keygrip = 1111000000000000000000000000000000000000
|
|
||||||
uid [ultimate] Alice Dev <adev@kernel.org>
|
|
||||||
sub rsa2048 2018-01-24 [E] [expires: 2020-01-24]
|
|
||||||
Keygrip = 2222000000000000000000000000000000000000
|
|
||||||
sub ed25519 2018-01-24 [S]
|
|
||||||
Keygrip = 3333000000000000000000000000000000000000
|
|
||||||
|
|
||||||
Find the keygrip entry that is beneath the `pub` line (right under the master
|
|
||||||
key fingerprint). This will correspond directly to a file in your `~/.gnupg`
|
|
||||||
directory:
|
|
||||||
|
|
||||||
$ cd ~/.gnupg/private-keys-v1.d
|
|
||||||
$ ls
|
|
||||||
1111000000000000000000000000000000000000.key
|
|
||||||
2222000000000000000000000000000000000000.key
|
|
||||||
3333000000000000000000000000000000000000.key
|
|
||||||
|
|
||||||
All you have to do is simply remove the `.key` file that corresponds to the
|
|
||||||
master keygrip:
|
|
||||||
|
|
||||||
$ cd ~/.gnupg/private-keys-v1.d
|
|
||||||
$ rm 1111000000000000000000000000000000000000.key
|
|
||||||
|
|
||||||
Now, if you issue the `--list-secret-keys` command, it will show that the
|
|
||||||
master key is missing (the `#` indicates it is not available):
|
|
||||||
|
|
||||||
$ gpg --list-secret-keys
|
|
||||||
sec# rsa2048 2018-01-24 [SC] [expires: 2020-01-24]
|
|
||||||
000000000000000000000000AAAABBBBCCCCDDDD
|
|
||||||
uid [ultimate] Alice Dev <adev@kernel.org>
|
|
||||||
ssb rsa2048 2018-01-24 [E] [expires: 2020-01-24]
|
|
||||||
ssb ed25519 2018-01-24 [S]
|
|
||||||
|
|
||||||
You should also remove any `secring.gpg` files in the `~/.gnupg` directory,
|
|
||||||
which are left over from earlier versions of GnuPG.
|
|
||||||
|
|
||||||
##### If you don't have the "private-keys-v1.d" directory
|
|
||||||
|
|
||||||
If you do not have a `~/.gnupg/private-keys-v1.d` directory, then your
|
|
||||||
secret keys are still stored in the legacy `secring.gpg` file used by GnuPG
|
|
||||||
v1. Making any changes to your key, such as changing the passphrase or adding
|
|
||||||
a subkey, should automatically convert the old `secring.gpg` format to use
|
|
||||||
`private-keys-v1.d` instead.
|
|
||||||
|
|
||||||
Once you get that done, make sure to delete the obsolete `secring.gpg` file,
|
|
||||||
which still contains your private keys.
|
|
||||||
|
|
||||||
## Move the subkeys to a dedicated crypto 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
|
|
||||||
|
|
||||||
Even though the master key is now safe from being leaked or stolen, the
|
|
||||||
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).
|
|
||||||
|
|
||||||
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 mounted, the operating system is able to access the private key
|
|
||||||
contents.
|
|
||||||
|
|
||||||
Using external encrypted USB media is not a substitute to having a
|
|
||||||
smartcard-capable device.
|
|
||||||
|
|
||||||
#### Available smartcard devices
|
|
||||||
|
|
||||||
Unless all your laptops and workstations have smartcard readers, the easiest
|
|
||||||
is to get a specialized USB device that implements smartcard functionality.
|
|
||||||
There are several options available:
|
|
||||||
|
|
||||||
- [Nitrokey Start](https://shop.nitrokey.com/shop/product/nitrokey-start-6):
|
|
||||||
Open hardware and Free Software, based on FSI Japan's
|
|
||||||
[Gnuk](http://www.fsij.org/doc-gnuk/). Offers support for ECC keys,
|
|
||||||
but fewest security features (such as resistance to tampering or some
|
|
||||||
side-channel attacks).
|
|
||||||
- [Nitrokey Pro](https://shop.nitrokey.com/shop/product/nitrokey-pro-3):
|
|
||||||
Similar to the Nitrokey Start, but more tamper-resistant and offers more
|
|
||||||
security features, but no ECC support.
|
|
||||||
- [Yubikey 4](https://www.yubico.com/product/yubikey-4-series/): Proprietary
|
|
||||||
hardware and software, but cheaper than Nitrokey Pro and comes available in
|
|
||||||
the USB-C form that is more useful with newer laptops. Offers
|
|
||||||
additional security features such as FIDO U2F, but no ECC.
|
|
||||||
|
|
||||||
[LWN has a good review](https://lwn.net/Articles/736231/) of some of the above
|
|
||||||
models, as well as several others. If you want to use ECC keys, your best bet
|
|
||||||
among commercially available devices is the Nitrokey Start.
|
|
||||||
|
|
||||||
#### Configuring your smartcard device
|
|
||||||
|
|
||||||
Your smartcard device should Just Work (TM) the moment you plug it into any
|
|
||||||
modern Linux workstation. You can verify it by running:
|
|
||||||
|
|
||||||
$ gpg --card-status
|
|
||||||
|
|
||||||
If you see full smartcard 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 help via usual support channels.
|
|
||||||
|
|
||||||
##### 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
|
|
||||||
[...omitted...]
|
|
||||||
gpg/card> admin
|
|
||||||
Admin commands are allowed
|
|
||||||
gpg/card> passwd
|
|
||||||
|
|
||||||
You should set the user PIN (1), Admin PIN (3), and the Reset Code (4). Please
|
|
||||||
make sure to record and store these in a safe place -- especially the Admin
|
|
||||||
PIN and the Reset Code (which allows you to completely wipe the smartcard).
|
|
||||||
You so rarely need to use the Admin PIN, that you will inevitably forget what
|
|
||||||
it is if you do not record it.
|
|
||||||
|
|
||||||
Getting back to the main card menu, you can also set other values (such as
|
|
||||||
name, sex, login data, etc), but it's not necessary and will additionally leak
|
|
||||||
information about your smartcard should you lose it.
|
|
||||||
|
|
||||||
##### 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.
|
|
||||||
|
|
||||||
#### Moving the subkeys to your smartcard
|
|
||||||
|
|
||||||
Exit the card menu (using "q") and save all changes. Next, let's move your
|
|
||||||
subkeys onto the smartcard. You will need both your PGP key passphrase and the
|
|
||||||
admin PIN of the card for most operations.
|
|
||||||
|
|
||||||
$ gpg --edit-key [fpr]
|
|
||||||
|
|
||||||
Secret subkeys are available.
|
|
||||||
|
|
||||||
pub rsa2048/AAAABBBBCCCCDDDD
|
|
||||||
created: 2018-01-23 expires: 2020-01-23 usage: SC
|
|
||||||
trust: ultimate validity: ultimate
|
|
||||||
ssb rsa2048/1111222233334444
|
|
||||||
created: 2018-01-23 expires: never usage: E
|
|
||||||
ssb ed25519/5555666677778888
|
|
||||||
created: 2017-12-07 expires: never usage: S
|
|
||||||
[ultimate] (1). Alice Dev <adev@kernel.org>
|
|
||||||
|
|
||||||
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, the **[E]** subkey):
|
|
||||||
|
|
||||||
gpg> key 1
|
|
||||||
|
|
||||||
In the output, you should now see `ssb*` on the **[E]** key. The `*` indicates
|
|
||||||
which key is currently "selected." It works as a *toggle*, meaning 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.
|
|
||||||
When you submit your selection, you will be prompted first for your PGP key
|
|
||||||
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.
|
|
||||||
|
|
||||||
gpg> q
|
|
||||||
Save changes? (y/N) y
|
|
||||||
|
|
||||||
Saving the changes will delete the keys you moved to the card from your home
|
|
||||||
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
|
|
||||||
sec# rsa2048 2018-01-24 [SC] [expires: 2020-01-24]
|
|
||||||
000000000000000000000000AAAABBBBCCCCDDDD
|
|
||||||
uid [ultimate] Alice Dev <adev@kernel.org>
|
|
||||||
ssb> rsa2048 2018-01-24 [E] [expires: 2020-01-24]
|
|
||||||
ssb> ed25519 2018-01-24 [S]
|
|
||||||
|
|
||||||
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
|
|
||||||
contents there, you will notice that the `.key` files there have been replaced
|
|
||||||
with stubs:
|
|
||||||
|
|
||||||
$ cd ~/.gnupg/private-keys-v1.d
|
|
||||||
$ strings *.key | grep 'private-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!
|
|
||||||
|
|
||||||
### Other common GnuPG operations
|
|
||||||
|
|
||||||
Here is a quick reference for some common operations you'll need to do with
|
|
||||||
your PGP key.
|
|
||||||
|
|
||||||
#### Mounting your master key offline storage
|
|
||||||
|
|
||||||
You will need your master key for any of the operations below, so you will
|
|
||||||
first need to mount your backup offline storage and tell GnuPG to use it.
|
|
||||||
|
|
||||||
$ export GNUPGHOME=/media/disk/name/gnupg-backup
|
|
||||||
$ gpg --list-secret-keys
|
|
||||||
|
|
||||||
You want to make sure that you see `sec` and not `sec#` in the output (the `#`
|
|
||||||
means the key is not available and you're still using your regular home
|
|
||||||
directory location).
|
|
||||||
|
|
||||||
##### 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:
|
|
||||||
|
|
||||||
$ gpg --export | gpg --homedir ~/.gnupg --import
|
|
||||||
$ unset GNUPGHOME
|
|
||||||
|
|
||||||
#### Extending key expiration date
|
|
||||||
|
|
||||||
The master key 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.
|
|
||||||
|
|
||||||
To extend the expiration on your key by a year from current date, just run:
|
|
||||||
|
|
||||||
$ gpg --quick-set-expire [fpr] 1y
|
|
||||||
|
|
||||||
You can also use a specific date if that is easier to remember (e.g. your
|
|
||||||
birthday, January 1st, or Canada Day):
|
|
||||||
|
|
||||||
$ gpg --quick-set-expire [fpr] 2020-07-01
|
|
||||||
|
|
||||||
Remember to send the updated key back to keyservers:
|
|
||||||
|
|
||||||
$ gpg --send-key [fpr]
|
|
||||||
|
|
||||||
## Using PGP with Git
|
|
||||||
|
|
||||||
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 their copy of
|
|
||||||
linux.git has not been tampered with by a malicious third party?
|
|
||||||
|
|
||||||
Or what happens if a backdoor is discovered in the code and the "Author" line
|
|
||||||
in the commit says it was done by you, while you're pretty sure you had
|
|
||||||
[nothing to do with it](https://github.com/jayphelps/git-blame-someone-else)?
|
|
||||||
|
|
||||||
To address both of these issues, Git introduced PGP integration. Signed tags
|
|
||||||
prove the repository integrity by assuring that its contents are exactly the
|
|
||||||
same as on the workstation of the developer who created the tag, while signed
|
|
||||||
commits make it nearly impossible for someone to impersonate you without
|
|
||||||
having access to your PGP keys.
|
|
||||||
|
|
||||||
### Checklist
|
|
||||||
|
|
||||||
- [ ] Configure git to use your key _(ESSENTIAL)_
|
|
||||||
- [ ] Configure git to always sign annotated tags _(NICE)_
|
|
||||||
- [ ] Decide if you're going to use commit signing _(NICE)_
|
|
||||||
|
|
||||||
### Considerations
|
|
||||||
|
|
||||||
#### 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.
|
|
||||||
|
|
||||||
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):
|
|
||||||
|
|
||||||
$ git config --global user.signingKey [fpr]
|
|
||||||
|
|
||||||
**IMPORTANT**: If you have a distinct `gpg2` command, then you should tell git
|
|
||||||
to always use it instead of the legacy `gpg` from version 1:
|
|
||||||
|
|
||||||
$ git config --global gpg.program gpg2
|
|
||||||
|
|
||||||
#### 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 pulling from has not been
|
|
||||||
maliciously altered.
|
|
||||||
|
|
||||||
##### How to verify signed tags
|
|
||||||
|
|
||||||
To verify a signed tag, simply use the `verify-tag` command:
|
|
||||||
|
|
||||||
$ git verify-tag [tagname]
|
|
||||||
|
|
||||||
If you are verifying someone else's git tag, then you will need to import
|
|
||||||
their PGP key. Please refer to the "how to verify kernel developer identities"
|
|
||||||
section below.
|
|
||||||
|
|
||||||
##### 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
|
|
||||||
use them in Linux Kernel development, since it relies on patches sent to
|
|
||||||
the mailing list, and this workflow does not preserve PGP commit signatures.
|
|
||||||
|
|
||||||
If you have your working git tree publicly available at some git hosting
|
|
||||||
service (kernel.org, infradead.org, ozlabs.org, or others), then the
|
|
||||||
recommendation is that you sign all your git commits even if upstream
|
|
||||||
developers do not directly benefit from this practice. Should there ever be a
|
|
||||||
need to perform code forensics or track code provenance, even externally
|
|
||||||
maintained trees carrying PGP commit signatures will be extremely valuable for
|
|
||||||
such purposes.
|
|
||||||
|
|
||||||
##### Creating signed commits
|
|
||||||
|
|
||||||
To create a signed commit, you just need to pass the `-S` flag to the `git
|
|
||||||
commit` command (it's capital `-S` due to collision with another flag):
|
|
||||||
|
|
||||||
$ git commit -S
|
|
||||||
|
|
||||||
#### Configure git to always sign commits
|
|
||||||
|
|
||||||
You can tell git to always sign commits:
|
|
||||||
|
|
||||||
git config --global commit.gpgSign true
|
|
||||||
|
|
||||||
Or you can train your muscle memory to always pass the `-S` flag to all `git
|
|
||||||
commit` operations (this includes `--amend`).
|
|
||||||
|
|
||||||
## How to verify kernel developer identities
|
|
||||||
|
|
||||||
Signing tags and commits is easy, but how does one go about verifying that the
|
|
||||||
key used to sign something belongs to the actual kernel developer and not to
|
|
||||||
a malicious imposter?
|
|
||||||
|
|
||||||
### Checklist
|
|
||||||
|
|
||||||
- [ ] Configure auto-key-retrieval using WKD and DANE _(ESSENTIAL)_
|
|
||||||
- [ ] Configure trust-model to `tofu+pgp` _(ESSENTIAL)_
|
|
||||||
- [ ] Learn how to use keyservers (more) safely _(ESSENTIAL)_
|
|
||||||
|
|
||||||
### Considerations
|
|
||||||
|
|
||||||
#### Configure auto-key-retrieval using WKD and DANE
|
|
||||||
|
|
||||||
If you are not already someone with an extensive collection of other
|
|
||||||
developers' public keys, then you can jumpstart your keyring by relying
|
|
||||||
on key auto-discovery and auto-retrieval. GnuPG can piggyback on other
|
|
||||||
delegated trust technologies, namely DNSSEC and TLS, to get you going if the
|
|
||||||
prospect of starting your own Web of Trust from scratch is too daunting.
|
|
||||||
|
|
||||||
Add the following to your `~/.gnupg/gpg.conf`:
|
|
||||||
|
|
||||||
auto-key-locate wkd,dane,local
|
|
||||||
auto-key-retrieve
|
|
||||||
|
|
||||||
DNS-Based Authentication of Named Entities ("DANE") is a method for publishing
|
|
||||||
public keys in DNS and securing them using DNSSEC signed zones. Web Key
|
|
||||||
Directory ("WKD") is the alternative method that uses https lookups for the
|
|
||||||
same purpose. When using either DANE or WKD for looking up public keys, GnuPG
|
|
||||||
will validate DNSSEC or TLS certificates, respectively, before adding
|
|
||||||
auto-retrieved public keys to your local keyring.
|
|
||||||
|
|
||||||
Kernel.org publishes the WKD for all developers who have kernel.org accounts.
|
|
||||||
Once you have the above changes in your `gpg.conf`, you can auto-retrieve the
|
|
||||||
keys for Linus Torvalds and Greg Kroah-Hartman (if you don't already have
|
|
||||||
them):
|
|
||||||
|
|
||||||
$ gpg --locate-keys torvalds@kernel.org gregkh@kernel.org
|
|
||||||
|
|
||||||
If you have a kernel.org account, then you should make sure that you have
|
|
||||||
[added the kernel.org UID to your key](https://korg.wiki.kernel.org/userdoc/mail#adding_a_kernelorg_uid_to_your_pgp_key)
|
|
||||||
to make WKD more useful to other kernel developers.
|
|
||||||
|
|
||||||
#### Web of Trust (WOT) vs. Trust on First Use (TOFU)
|
|
||||||
|
|
||||||
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
|
|
||||||
Authorities of the HTTPS/TLS world. Instead of various software makers
|
|
||||||
dictating who should be your trusted certifying entity, PGP leaves this
|
|
||||||
responsibility to each user.
|
|
||||||
|
|
||||||
Unfortunately, very few people understand how the Web of Trust works. While
|
|
||||||
it remains an important aspect of the OpenPGP specification, 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
|
|
||||||
valid. 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
|
|
||||||
as invalid and you will need to manually figure out which one to keep.
|
|
||||||
|
|
||||||
We recommend that you use the combined TOFU+PGP trust model (which is the new
|
|
||||||
default in GnuPG v2). To set it, add (or modify) the `trust-model` setting in
|
|
||||||
`~/.gnupg/gpg.conf`:
|
|
||||||
|
|
||||||
trust-model tofu+pgp
|
|
||||||
|
|
||||||
#### Learn to use keyservers (more) safely
|
|
||||||
|
|
||||||
If, despite setting `auto-key-retrieve`, you still get a "No public key" error
|
|
||||||
when trying to validate someone's tag, then you should attempt to lookup that
|
|
||||||
key using a keyserver. It is important to keep in mind that there is
|
|
||||||
absolutely no guarantee that the key you retrieve from a keyserver belongs to
|
|
||||||
the actual person -- that much is by design. You are supposed to use the Web
|
|
||||||
of Trust to establish key validity.
|
|
||||||
|
|
||||||
How to properly maintain the Web of Trust is beyond the scope of this
|
|
||||||
document, simply because doing it properly requires both effort and dedication
|
|
||||||
that tends to be beyond the caring threshold of most human beings. Here are
|
|
||||||
some shortcuts that will help you reduce the risk of importing a malicious
|
|
||||||
key.
|
|
||||||
|
|
||||||
First, let's say you've tried to run `git verify-tag` but it returned an error
|
|
||||||
saying the key is not found:
|
|
||||||
|
|
||||||
$ git verify-tag sunxi-fixes-for-4.15-2
|
|
||||||
gpg: Signature made Sun 07 Jan 2018 10:51:55 PM EST
|
|
||||||
gpg: using RSA key DA73759BF8619E484E5A3B47389A54219C0F2430
|
|
||||||
gpg: issuer "wens@...org"
|
|
||||||
gpg: Can't check signature: No public key
|
|
||||||
|
|
||||||
Let's query the keyserver for more info about that key fingerprint (the
|
|
||||||
fingerprint probably belongs to a subkey, so we can't use it directly without
|
|
||||||
finding out the ID of the master key it is associated with):
|
|
||||||
|
|
||||||
$ gpg --search DA73759BF8619E484E5A3B47389A54219C0F2430
|
|
||||||
gpg: data source: hkp://keys.gnupg.net
|
|
||||||
(1) Chen-Yu Tsai <wens@...org>
|
|
||||||
4096 bit RSA key C94035C21B4F2AEB, created: 2017-03-14, expires: 2019-03-15
|
|
||||||
Keys 1-1 of 1 for "DA73759BF8619E484E5A3B47389A54219C0F2430". Enter number(s), N)ext, or Q)uit > q
|
|
||||||
|
|
||||||
Locate the ID of the master key in the output, in our example
|
|
||||||
`C94035C21B4F2AEB`. Now say `q` and display the key of Linus Torvalds that you
|
|
||||||
have on your keyring:
|
|
||||||
|
|
||||||
$ git --list-key torvalds@kernel.org
|
|
||||||
pub rsa2048 2011-09-20 [SC]
|
|
||||||
ABAF11C65A2970B130ABE3C479BE3E4300411886
|
|
||||||
uid [ unknown] Linus Torvalds <torvalds@kernel.org>
|
|
||||||
sub rsa2048 2011-09-20 [E]
|
|
||||||
|
|
||||||
Next, open the [PGP pathfinder](https://pgp.cs.uu.nl/). In the "From" field,
|
|
||||||
paste the key fingerprint of Linus Torvalds from the output above. In the "To"
|
|
||||||
field, paste they key-id you found via `gpg --search` of the unknown key, and
|
|
||||||
check the results:
|
|
||||||
|
|
||||||
- [From Linus to Chen-Yu](https://pgp.cs.uu.nl/paths/79BE3E4300411886/to/C94035C21B4F2AEB.html)
|
|
||||||
|
|
||||||
If you get a few decent trust paths, then it's a pretty good indication that
|
|
||||||
it is a valid key. You can add it to your keyring from the keyserver now:
|
|
||||||
|
|
||||||
$ gpg --recv-key C94035C21B4F2AEB
|
|
||||||
|
|
||||||
This process is not perfect, and you are obviously trusting the administrators
|
|
||||||
of the PGP Pathfinder service to not be malicious. However, if you do not
|
|
||||||
carefully maintain your own web of trust, then it is an improvement over
|
|
||||||
blindly trusting keyservers.
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Protecting code integrity with PGP
|
# Protecting code integrity with PGP
|
||||||
|
|
||||||
Updated: 2018-01-22
|
Updated: 2021-05-13
|
||||||
|
|
||||||
*Status: CURRENT*
|
*Status: CURRENT*
|
||||||
|
|
||||||
|
@ -23,35 +23,31 @@ Updated: 2018-01-22
|
||||||
- [Web of Trust (WOT) vs. Trust on First Use (TOFU)](#web-of-trust-wot-vs-trust-on-first-use-tofu)
|
- [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 OpenPGP software](#installing-openpgp-software)
|
||||||
- [Installing GnuPG](#installing-gnupg)
|
- [Installing GnuPG](#installing-gnupg)
|
||||||
- [GnuPG 1 vs. 2](#gnupg-1-vs-2)
|
- [Generating and protecting your certification key](#generating-and-protecting-your-certification-key)
|
||||||
- [Making sure you always use GnuPG v.2](#making-sure-you-always-use-gnupg-v2)
|
|
||||||
- [Generating and protecting your master PGP key](#generating-and-protecting-your-master-pgp-key)
|
|
||||||
- [Checklist](#checklist-1)
|
- [Checklist](#checklist-1)
|
||||||
- [Considerations](#considerations-1)
|
- [Considerations](#considerations-1)
|
||||||
- [Understanding the "Master" (Certify) key](#understanding-the-%22master%22-certify-key)
|
- [Understanding the certification key](#understanding-the-certification-key)
|
||||||
- [Before you create the master key](#before-you-create-the-master-key)
|
- [Before you create the certification key](#before-you-create-the-certification-key)
|
||||||
- [Primary identity](#primary-identity)
|
- [Primary identity](#primary-identity)
|
||||||
- [Passphrase](#passphrase)
|
- [Passphrase](#passphrase)
|
||||||
- [Algorithm and key strength](#algorithm-and-key-strength)
|
- [Algorithm and key strength](#algorithm-and-key-strength)
|
||||||
- [Generate the master key](#generate-the-master-key)
|
- [Generate the certification key](#generate-the-certification-key)
|
||||||
- [Back up your master key](#back-up-your-master-key)
|
- [Back up your certification key](#back-up-your-certification-key)
|
||||||
- [Add relevant identities](#add-relevant-identities)
|
- [Add relevant identities](#add-relevant-identities)
|
||||||
- [Pick the primary UID](#pick-the-primary-uid)
|
- [Pick the primary UID](#pick-the-primary-uid)
|
||||||
- [Generating PGP subkeys](#generating-pgp-subkeys)
|
- [Generating PGP subkeys](#generating-pgp-subkeys)
|
||||||
- [Checklist](#checklist-2)
|
- [Checklist](#checklist-2)
|
||||||
- [Considerations](#considerations-2)
|
- [Considerations](#considerations-2)
|
||||||
- [Create the subkeys](#create-the-subkeys)
|
- [Create the subkeys](#create-the-subkeys)
|
||||||
- [Upload your public keys to the keyserver](#upload-your-public-keys-to-the-keyserver)
|
|
||||||
- [Upload your public key to GitHub](#upload-your-public-key-to-github)
|
- [Upload your public key to GitHub](#upload-your-public-key-to-github)
|
||||||
- [Set up a refresh cronjob](#set-up-a-refresh-cronjob)
|
- [Moving your certification key to offline storage](#moving-your-certification-key-to-offline-storage)
|
||||||
- [Moving your master key to offline storage](#moving-your-master-key-to-offline-storage)
|
|
||||||
- [Checklist](#checklist-3)
|
- [Checklist](#checklist-3)
|
||||||
- [Considerations](#considerations-3)
|
- [Considerations](#considerations-3)
|
||||||
- [Back up your GnuPG directory](#back-up-your-gnupg-directory)
|
- [Back up your GnuPG directory](#back-up-your-gnupg-directory)
|
||||||
- [Prepare detachable encrypted storage](#prepare-detachable-encrypted-storage)
|
- [Prepare detachable encrypted storage](#prepare-detachable-encrypted-storage)
|
||||||
- [Back up your GnuPG directory](#back-up-your-gnupg-directory-1)
|
- [Back up your GnuPG directory](#back-up-your-gnupg-directory-1)
|
||||||
- [Remove the master key](#remove-the-master-key)
|
- [Remove the certification key](#remove-the-certification-key)
|
||||||
- [Removing your master key](#removing-your-master-key)
|
- [Removing your certification key](#removing-your-certification-key)
|
||||||
- [Remove the revocation certificate](#remove-the-revocation-certificate)
|
- [Remove the revocation certificate](#remove-the-revocation-certificate)
|
||||||
- [Move the subkeys to a hardware device](#move-the-subkeys-to-a-hardware-device)
|
- [Move the subkeys to a hardware device](#move-the-subkeys-to-a-hardware-device)
|
||||||
- [Checklist](#checklist-4)
|
- [Checklist](#checklist-4)
|
||||||
|
@ -65,7 +61,7 @@ Updated: 2018-01-22
|
||||||
- [Verifying that the keys were moved](#verifying-that-the-keys-were-moved)
|
- [Verifying that the keys were moved](#verifying-that-the-keys-were-moved)
|
||||||
- [Verifying that the smartcard is functioning](#verifying-that-the-smartcard-is-functioning)
|
- [Verifying that the smartcard is functioning](#verifying-that-the-smartcard-is-functioning)
|
||||||
- [Other common GnuPG operations](#other-common-gnupg-operations)
|
- [Other common GnuPG operations](#other-common-gnupg-operations)
|
||||||
- [Mounting your master key offline storage](#mounting-your-master-key-offline-storage)
|
- [Mounting your offline storage](#mounting-your-offline-storage)
|
||||||
- [Updating your regular GnuPG working directory](#updating-your-regular-gnupg-working-directory)
|
- [Updating your regular GnuPG working directory](#updating-your-regular-gnupg-working-directory)
|
||||||
- [Extending key expiration date](#extending-key-expiration-date)
|
- [Extending key expiration date](#extending-key-expiration-date)
|
||||||
- [Revoking identities](#revoking-identities)
|
- [Revoking identities](#revoking-identities)
|
||||||
|
@ -78,7 +74,6 @@ Updated: 2018-01-22
|
||||||
- [Hashing function](#hashing-function)
|
- [Hashing function](#hashing-function)
|
||||||
- [Annotated tags and tag signatures](#annotated-tags-and-tag-signatures)
|
- [Annotated tags and tag signatures](#annotated-tags-and-tag-signatures)
|
||||||
- [Signed commits](#signed-commits)
|
- [Signed commits](#signed-commits)
|
||||||
- [Signed pushes](#signed-pushes)
|
|
||||||
- [Configure git to use your PGP key](#configure-git-to-use-your-pgp-key)
|
- [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 work with signed tags](#how-to-work-with-signed-tags)
|
||||||
- [How to verify signed tags](#how-to-verify-signed-tags)
|
- [How to verify signed tags](#how-to-verify-signed-tags)
|
||||||
|
@ -325,66 +320,39 @@ 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
|
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.
|
research to find the correct places to download and install GnuPG.
|
||||||
|
|
||||||
##### GnuPG 1 vs. 2
|
## Generating and protecting your certification key
|
||||||
|
|
||||||
Both GnuPG v.1 and GnuPG v.2 implement the same standard, but they provide
|
|
||||||
incompatible libraries and command-line tools, so many distributions ship both
|
|
||||||
the legacy version 1 and the latest version 2. You need to make sure you are
|
|
||||||
always using GnuPG v.2.
|
|
||||||
|
|
||||||
First, run:
|
|
||||||
|
|
||||||
$ gpg --version | head -n1
|
|
||||||
|
|
||||||
If you see `gpg (GnuPG) 1.4.x`, then you are using GnuPG v.1. Try the `gpg2`
|
|
||||||
command:
|
|
||||||
|
|
||||||
$ gpg2 --version | head -n1
|
|
||||||
|
|
||||||
If you see `gpg (GnuPG) 2.x.x`, then you are good to go. This guide will
|
|
||||||
assume you have the version 2.2 of GnuPG (or later). If you are using version
|
|
||||||
2.0 of GnuPG, some of the commands in this guide will not work, and you should
|
|
||||||
consider installing the latest 2.2 version of GnuPG.
|
|
||||||
|
|
||||||
##### Making sure you always use GnuPG v.2
|
|
||||||
|
|
||||||
If you have both `gpg` and `gpg2` commands, you should make sure you are
|
|
||||||
always using GnuPG v2, not the legacy version. You can make sure of this by
|
|
||||||
setting the alias:
|
|
||||||
|
|
||||||
$ alias gpg=gpg2
|
|
||||||
|
|
||||||
You can put that in your `.bashrc` to make sure it's always loaded whenever
|
|
||||||
you use the gpg commands.
|
|
||||||
|
|
||||||
## Generating and protecting your master PGP key
|
|
||||||
|
|
||||||
### Checklist
|
### Checklist
|
||||||
|
|
||||||
- [ ] Generate a 4096-bit RSA master key _(ESSENTIAL)_
|
- [ ] Generate a 4096-bit RSA certification key _(ESSENTIAL)_
|
||||||
- [ ] Back up the master key using paperkey _(ESSENTIAL)_
|
- [ ] Back up the certification key using paperkey _(ESSENTIAL)_
|
||||||
- [ ] Add all relevant identities _(ESSENTIAL)_
|
- [ ] Add all relevant identities _(ESSENTIAL)_
|
||||||
|
|
||||||
### Considerations
|
### Considerations
|
||||||
|
|
||||||
#### Understanding the "Master" (Certify) key
|
#### Understanding the certification key
|
||||||
|
|
||||||
In this and next section we'll talk about the "master key" and "subkeys". It
|
In this and next section we'll talk about the certification key and subkeys.
|
||||||
is important to understand the following:
|
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."
|
||||||
|
|
||||||
1. There are no technical differences between the "master key" and "subkeys."
|
It is important to understand the following:
|
||||||
|
|
||||||
|
1. There are no technical differences between the certify key and any of the
|
||||||
|
subkeys
|
||||||
2. At creation time, we assign functional limitations to each key by
|
2. At creation time, we assign functional limitations to each key by
|
||||||
giving it specific capabilities.
|
giving it specific capabilities.
|
||||||
3. A PGP key can have 4 capabilities.
|
3. A PGP key can have 4 capabilities:
|
||||||
- **[S]** key can be used for signing
|
- **[S]** key can be used for signing
|
||||||
- **[E]** key can be used for encryption
|
- **[E]** key can be used for encryption
|
||||||
- **[A]** key can be used for authentication
|
- **[A]** key can be used for authentication
|
||||||
- **[C]** key can be used for certifying other keys
|
- **[C]** key can be used for certifying other keys
|
||||||
4. A single key may have multiple capabilities.
|
4. A single key may have multiple capabilities.
|
||||||
|
|
||||||
The key carrying the **[C]** (certify) capability is considered the "master"
|
The key carrying the **[C]** (certify) capability is used to indicate
|
||||||
key because it is the only key that can be used to indicate relationship with
|
relationship with other PGP keys. Only the **[C]** key can be used to:
|
||||||
other keys. Only the **[C]** key can be used to:
|
|
||||||
|
|
||||||
- add or revoke other keys (subkeys) with S/E/A capabilities
|
- add or revoke other keys (subkeys) with S/E/A capabilities
|
||||||
- add, change or revoke identities (uids) associated with the key
|
- add, change or revoke identities (uids) associated with the key
|
||||||
|
@ -395,10 +363,10 @@ In the Free Software world, the **[C]** key is your digital identity. Once you
|
||||||
create that key, you should take extra care to protect it and prevent it from
|
create that key, you should take extra care to protect it and prevent it from
|
||||||
falling into malicious hands.
|
falling into malicious hands.
|
||||||
|
|
||||||
#### Before you create the master key
|
#### Before you create the certify key
|
||||||
|
|
||||||
Before you create your master key you need to pick your primary identity and
|
Before you create your certify key you need to pick your primary identity and
|
||||||
your master passphrase.
|
your passphrase.
|
||||||
|
|
||||||
##### Primary identity
|
##### Primary identity
|
||||||
|
|
||||||
|
@ -428,23 +396,24 @@ to type and easy to remember.
|
||||||
|
|
||||||
##### Algorithm and key strength
|
##### Algorithm and key strength
|
||||||
|
|
||||||
Even though GnuPG has had support for Elliptic Curve crypto for a while now,
|
GnuPG supports many algorithms, but we will only consider the below two:
|
||||||
we'll be sticking to RSA keys, at least for a little while longer. While it is
|
|
||||||
possible to start using ED25519 keys right now, it is likely that you will
|
|
||||||
come across tools and hardware devices that will not be able to handle them
|
|
||||||
correctly.
|
|
||||||
|
|
||||||
You may also wonder why the master key is 4096-bit, if later in the guide we
|
- RSA for the certification key
|
||||||
state that 2048-bit keys should be good enough for the lifetime of RSA public
|
- ECC (Elliptic Curve) for all other subkeys
|
||||||
key cryptography. The reasons are mostly social and not technical: master keys
|
|
||||||
happen to be the most visible ones on the keychain, and some of the developers
|
|
||||||
you interact with will inevitably judge you negatively if your master key has
|
|
||||||
fewer bits than theirs.
|
|
||||||
|
|
||||||
#### Generate the master key
|
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.
|
||||||
|
|
||||||
To generate your new master key, issue the following command, putting in the
|
All of the day-to-day work will be done using subkeys, so picking ECC makes
|
||||||
right values instead of "Alice Engineer:"
|
perfect sense there -- it will be faster and the resulting signatures will be
|
||||||
|
dramatically smaller.
|
||||||
|
|
||||||
|
#### Generate the certification key
|
||||||
|
|
||||||
|
To generate your new certification key, issue the following command, putting
|
||||||
|
in the right values instead of "Alice Engineer:"
|
||||||
|
|
||||||
$ gpg --quick-generate-key 'Alice Engineer <alice@example.org>' rsa4096 cert
|
$ gpg --quick-generate-key 'Alice Engineer <alice@example.org>' rsa4096 cert
|
||||||
|
|
||||||
|
@ -454,7 +423,7 @@ the command completes.
|
||||||
|
|
||||||
Review the output of the command, it will be something like this:
|
Review the output of the command, it will be something like this:
|
||||||
|
|
||||||
pub rsa4096 2017-12-06 [C] [expires: 2019-12-06]
|
pub rsa4096 2021-05-01 [C] [expires: 2023-05-01]
|
||||||
111122223333444455556666AAAABBBBCCCCDDDD
|
111122223333444455556666AAAABBBBCCCCDDDD
|
||||||
uid Alice Engineer <alice@example.org>
|
uid Alice Engineer <alice@example.org>
|
||||||
|
|
||||||
|
@ -472,7 +441,7 @@ At this point, I suggest you open a text editor, copy the fingerprint of your
|
||||||
new key and paste it there. You'll need to use it for the next few steps, so
|
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.
|
having it close by will be handy.
|
||||||
|
|
||||||
#### Back up your master key
|
#### Back up your certification key
|
||||||
|
|
||||||
For disaster recovery purposes -- and especially if you intend to use the Web
|
For disaster recovery purposes -- and especially if you intend to use the Web
|
||||||
of Trust and collect key signatures from other project developers -- you
|
of Trust and collect key signatures from other project developers -- you
|
||||||
|
@ -508,9 +477,9 @@ safe operation, but use your best paranoid judgement.
|
||||||
#### Add relevant identities
|
#### Add relevant identities
|
||||||
|
|
||||||
If you have multiple relevant email addresses (personal, work, open-source
|
If you have multiple relevant email addresses (personal, work, open-source
|
||||||
project, etc), you should add them to your master key. You don't need to do
|
project, etc), you should add them to your key. You don't need to do this for
|
||||||
this for any addresses that you don't expect to use with PGP (e.g. probably
|
any addresses that you don't expect to use with PGP (e.g. probably not your
|
||||||
not your school alumni address).
|
school alumni address).
|
||||||
|
|
||||||
The command is (put the full key fingerprint instead of `[fpr]`):
|
The command is (put the full key fingerprint instead of `[fpr]`):
|
||||||
|
|
||||||
|
@ -531,78 +500,58 @@ different from what you want, you should fix it back:
|
||||||
|
|
||||||
### Checklist
|
### Checklist
|
||||||
|
|
||||||
- [ ] Generate a 2048-bit Encryption subkey _(ESSENTIAL)_
|
- [ ] Generate the Encryption subkey _(ESSENTIAL)_
|
||||||
- [ ] Generate a 2048-bit Signing subkey _(ESSENTIAL)_
|
- [ ] Generate the Signing subkey _(ESSENTIAL)_
|
||||||
- [ ] Generate a 2048-bit Authentication subkey _(NICE)_
|
- [ ] Generate the Authentication subkey _(NICE)_
|
||||||
- [ ] Upload your public keys to a PGP keyserver _(ESSENTIAL)_
|
- [ ] Upload your public keys to a PGP keyserver _(NICE)_
|
||||||
- [ ] Set up a refresh cronjob _(ESSENTIAL)_
|
- [ ] Set up a refresh cronjob _(NICE)_
|
||||||
|
|
||||||
### Considerations
|
### Considerations
|
||||||
|
|
||||||
Now that we've created the master key, let's create the keys you'll actually
|
Now that we've created the certification key, let's create the keys you'll
|
||||||
be using for day-to-day work. We create 2048-bit keys because a lot of
|
actually be using for day-to-day work. Before we do this, we need to pick the
|
||||||
specialized hardware (we'll discuss this further) does not handle larger keys,
|
ECC algorithm flavor.
|
||||||
but also for pragmatic reasons. If we ever find ourselves in a world where
|
|
||||||
2048-bit RSA keys are not considered good enough, it will be because of
|
#### ED25519 or NIST?
|
||||||
fundamental breakthroughs in computing or mathematics and therefore longer
|
|
||||||
4096-bit keys will not make much difference.
|
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.
|
||||||
|
|
||||||
#### Create the subkeys
|
#### Create the subkeys
|
||||||
|
|
||||||
To create the subkeys, run:
|
To create the subkeys, run:
|
||||||
|
|
||||||
$ gpg --quick-add-key [fpr] rsa2048 encr
|
$ gpg --quick-add-key [fpr] cv25519 encr
|
||||||
$ gpg --quick-add-key [fpr] rsa2048 sign
|
$ gpg --quick-add-key [fpr] ed25519 sign
|
||||||
|
|
||||||
You can also create the Authentication key, which will allow you to use your
|
You can also create the Authentication key, which will allow you to use your
|
||||||
PGP key for ssh purposes:
|
PGP key for ssh purposes:
|
||||||
|
|
||||||
$ gpg --quick-add-key [fpr] rsa2048 auth
|
$ gpg --quick-add-key [fpr] ed25519 auth
|
||||||
|
|
||||||
You can review your key information using `gpg --list-key [fpr]`:
|
You can review your key information using `gpg --list-key [fpr]`:
|
||||||
|
|
||||||
pub rsa4096 2017-12-06 [C] [expires: 2019-12-06]
|
pub rsa4096 2021-05-01 [C] [expires: 2023-05-01]
|
||||||
111122223333444455556666AAAABBBBCCCCDDDD
|
111122223333444455556666AAAABBBBCCCCDDDD
|
||||||
uid [ultimate] Alice Engineer <alice@example.org>
|
uid [ultimate] Alice Engineer <alice@example.org>
|
||||||
uid [ultimate] Alice Engineer <allie@example.net>
|
uid [ultimate] Alice Engineer <allie@example.net>
|
||||||
sub rsa2048 2017-12-06 [E]
|
sub cv25519 2021-05-01 [E]
|
||||||
sub rsa2048 2017-12-06 [S]
|
sub ed25519 2021-05-01 [S]
|
||||||
|
|
||||||
#### Upload your public keys to the keyserver
|
#### Upload your public key to GitHub
|
||||||
|
|
||||||
Your key creation is complete, so now you need to make it easier for others to
|
If you use GitHub in your development, you should upload your key following
|
||||||
find it by uploading it to one of the public keyservers. (Do not do this step
|
the instructions they have provided:
|
||||||
if you're just messing around and aren't planning on actually using the key
|
|
||||||
you've created, as this just litters keyservers with useless data.)
|
|
||||||
|
|
||||||
$ gpg --send-key [fpr]
|
|
||||||
|
|
||||||
If this command does not succeed, you can try specifying the keyserver on a
|
|
||||||
port that is most likely to work:
|
|
||||||
|
|
||||||
$ gpg --keyserver hkp://pgp.mit.edu:80 --send-key [fpr]
|
|
||||||
|
|
||||||
Most keyservers communicate with each-other, so your key information will
|
|
||||||
eventually synchronize to all the others.
|
|
||||||
|
|
||||||
**NOTE ON PRIVACY:** Keyservers are completely public and therefore, by
|
|
||||||
design, leak potentially sensitive information about you, such as your full
|
|
||||||
name, nicknames, and personal or work email addresses. If you sign other
|
|
||||||
people's keys or someone signs yours, keyservers will additionally become
|
|
||||||
leakers of your social connections. Once such personal information makes it to
|
|
||||||
the keyservers, it becomes impossible to edit or delete. Even if you revoke a
|
|
||||||
signature or identity, that does not delete them from your key record, just
|
|
||||||
marks them as revoked -- making them stand out even more.
|
|
||||||
|
|
||||||
That said, if you participate in software development on a public project, all
|
|
||||||
of the above information is already public record, and therefore making it
|
|
||||||
additionally available via keyservers does not result in a net loss in
|
|
||||||
privacy.
|
|
||||||
|
|
||||||
##### Upload your public key to GitHub
|
|
||||||
|
|
||||||
If you use GitHub in your development (and who doesn't?), you should upload
|
|
||||||
your key following the instructions they have provided:
|
|
||||||
|
|
||||||
- [Adding a PGP key to your GitHub account](https://help.github.com/articles/adding-a-new-gpg-key-to-your-github-account/)
|
- [Adding a PGP key to your GitHub account](https://help.github.com/articles/adding-a-new-gpg-key-to-your-github-account/)
|
||||||
|
|
||||||
|
@ -610,39 +559,33 @@ To generate the public key output suitable to paste in, just run:
|
||||||
|
|
||||||
$ gpg --export --armor [fpr]
|
$ gpg --export --armor [fpr]
|
||||||
|
|
||||||
#### Set up a refresh cronjob
|
#### Upload your public key to keys.openpgp.org
|
||||||
|
|
||||||
You will need to regularly refresh your keyring in order to get the latest
|
To make it easier for others to find your public key, you can upload it to the
|
||||||
changes on other people's public keys. You can set up a cronjob to do that:
|
keys.openpgp.org keyserver. Please follow the instructions provided here:
|
||||||
|
|
||||||
$ crontab -e
|
- [Upload to keys.openpgp.org](https://keys.openpgp.org/about/usage#gnupg-upload)
|
||||||
|
|
||||||
Add the following on a new line:
|
|
||||||
|
|
||||||
@daily /usr/bin/gpg2 --refresh >/dev/null 2>&1
|
## Moving your cerification key to offline storage
|
||||||
|
|
||||||
**NOTE**: check the full path to your `gpg` or `gpg2` command and use the `gpg2`
|
|
||||||
command if regular `gpg` for you is the legacy GnuPG v.1.
|
|
||||||
|
|
||||||
## Moving your master key to offline storage
|
|
||||||
|
|
||||||
### Checklist
|
### Checklist
|
||||||
|
|
||||||
- [ ] Prepare encrypted detachable storage _(ESSENTIAL)_
|
- [ ] Prepare encrypted detachable storage _(ESSENTIAL)_
|
||||||
- [ ] Back up your GnuPG directory _(ESSENTIAL)_
|
- [ ] Back up your GnuPG directory _(ESSENTIAL)_
|
||||||
- [ ] Remove the master key from your home directory _(NICE)_
|
- [ ] Remove the certification key from your home directory _(NICE)_
|
||||||
- [ ] Remove the revocation certificate from your home directory _(NICE)_
|
- [ ] Remove the revocation certificate from your home directory _(NICE)_
|
||||||
|
|
||||||
### Considerations
|
### Considerations
|
||||||
|
|
||||||
Why would you want to remove your master **[C]** key from your home directory?
|
Why would you want to remove your certification (**[C]**) key from your home
|
||||||
This is generally done to prevent your master key from being stolen or
|
directory? This is generally done to prevent it from being stolen or
|
||||||
accidentally leaked. Private keys are tasty targets for malicious actors -- we
|
accidentally leaked. Private keys are tasty targets for malicious actors --
|
||||||
know this from several successful malware attacks that scanned users' home
|
we know this from several successful malware attacks that scanned users' home
|
||||||
directories and uploaded any private key content found there.
|
directories and uploaded any private key content found there.
|
||||||
|
|
||||||
It would be very damaging for any developer to have their PGP keys stolen --
|
It would be very damaging for any developer to have their PGP keys stolen --
|
||||||
in the Free Software world this is often tantamount to identity theft.
|
in the Free Software world this is basically equal to identity theft.
|
||||||
Removing private keys from your home directory helps protect you from such
|
Removing private keys from your home directory helps protect you from such
|
||||||
events.
|
events.
|
||||||
|
|
||||||
|
@ -662,7 +605,8 @@ for backup purposes. You will first need to encrypt them:
|
||||||
- [Apple instructions](https://support.apple.com/kb/PH25745)
|
- [Apple instructions](https://support.apple.com/kb/PH25745)
|
||||||
- [Linux instructions](https://help.ubuntu.com/community/EncryptedFilesystemsOnRemovableStorage)
|
- [Linux instructions](https://help.ubuntu.com/community/EncryptedFilesystemsOnRemovableStorage)
|
||||||
|
|
||||||
For the encryption passphrase, you can use the same one as on your master key.
|
For the encryption passphrase, you can use the same one as on your private
|
||||||
|
key.
|
||||||
|
|
||||||
#### Back up your GnuPG directory
|
#### Back up your GnuPG directory
|
||||||
|
|
||||||
|
@ -688,7 +632,7 @@ a random USB drive, and put in a safe place -- but not too far away, because
|
||||||
you'll need to use it every now and again for things like editing identities,
|
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.
|
adding or revoking subkeys, or signing other people's keys.
|
||||||
|
|
||||||
#### Remove the master key
|
#### Remove the certification key
|
||||||
|
|
||||||
The files in our home directory are not as well protected as we like to think.
|
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:
|
They can be leaked or stolen via many different means:
|
||||||
|
@ -702,32 +646,32 @@ They can be leaked or stolen via many different means:
|
||||||
Protecting your key with a good passphrase greatly helps reduce the risk of
|
Protecting your key with a good passphrase greatly helps reduce the risk of
|
||||||
any of the above, but passphrases can be discovered via keyloggers,
|
any of the above, but passphrases can be discovered via keyloggers,
|
||||||
shoulder-surfing, or any number of other means. For this reason, the
|
shoulder-surfing, or any number of other means. For this reason, the
|
||||||
recommended setup is to remove your master key from your home directory and
|
recommended setup is to remove your certification key from your home directory
|
||||||
store it on offline storage.
|
and store it on offline storage.
|
||||||
|
|
||||||
##### Removing your master key
|
##### Removing your certification key
|
||||||
|
|
||||||
Please see the previous section and make sure you have backed up your GnuPG
|
Please see the previous section and make sure you have backed up your GnuPG
|
||||||
directory in its entirety. What we are about to do will render your key
|
directory in its entirety. What we are about to do will render your key
|
||||||
useless if you do not have a usable backup!
|
useless if you do not have a usable backup!
|
||||||
|
|
||||||
First, identify the keygrip of your master key:
|
First, identify the "keygrip" of your certification key:
|
||||||
|
|
||||||
$ gpg --with-keygrip --list-key [fpr]
|
$ gpg --with-keygrip --list-key [fpr]
|
||||||
|
|
||||||
The output will be something like this:
|
The output will be something like this:
|
||||||
|
|
||||||
pub rsa4096 2017-12-06 [C] [expires: 2019-12-06]
|
pub rsa4096 2021-05-01 [C] [expires: 2023-05-01]
|
||||||
111122223333444455556666AAAABBBBCCCCDDDD
|
111122223333444455556666AAAABBBBCCCCDDDD
|
||||||
Keygrip = AAAA999988887777666655554444333322221111
|
Keygrip = AAAA999988887777666655554444333322221111
|
||||||
uid [ultimate] Alice Engineer <alice@example.org>
|
uid [ultimate] Alice Engineer <alice@example.org>
|
||||||
uid [ultimate] Alice Engineer <allie@example.net>
|
uid [ultimate] Alice Engineer <allie@example.net>
|
||||||
sub rsa2048 2017-12-06 [E]
|
sub cv25519 2021-05-01 [E]
|
||||||
Keygrip = BBBB999988887777666655554444333322221111
|
Keygrip = BBBB999988887777666655554444333322221111
|
||||||
sub rsa2048 2017-12-06 [S]
|
sub ed25519 2021-05-01 [S]
|
||||||
Keygrip = CCCC999988887777666655554444333322221111
|
Keygrip = CCCC999988887777666655554444333322221111
|
||||||
|
|
||||||
Find the keygrip entry that is beneath the `pub` line (right under the master
|
Find the keygrip entry that is beneath the `pub` line (right under the public
|
||||||
key fingerprint). This will correspond directly to a file in your home
|
key fingerprint). This will correspond directly to a file in your home
|
||||||
`.gnupg` directory:
|
`.gnupg` directory:
|
||||||
|
|
||||||
|
@ -738,34 +682,34 @@ key fingerprint). This will correspond directly to a file in your home
|
||||||
CCCC999988887777666655554444333322221111.key
|
CCCC999988887777666655554444333322221111.key
|
||||||
|
|
||||||
All you have to do is simply remove the `.key` file that corresponds to the
|
All you have to do is simply remove the `.key` file that corresponds to the
|
||||||
master keygrip:
|
certification keygrip:
|
||||||
|
|
||||||
$ cd ~/.gnupg/private-keys-v1.d
|
$ cd ~/.gnupg/private-keys-v1.d
|
||||||
$ rm AAAA999988887777666655554444333322221111.key
|
$ rm AAAA999988887777666655554444333322221111.key
|
||||||
|
|
||||||
Now, if you issue the `--list-secret-keys` command, it will show that the
|
Now, if you issue the `--list-secret-keys` command, it will show that the
|
||||||
master key is missing (the `#` indicates it is not available):
|
**[C]** key is not present (indicated by the `#` character):
|
||||||
|
|
||||||
$ gpg --list-secret-keys
|
$ gpg --list-secret-keys
|
||||||
sec# rsa4096 2017-12-06 [C] [expires: 2019-12-06]
|
sec# rsa4096 2021-05-01 [C] [expires: 2023-05-01]
|
||||||
111122223333444455556666AAAABBBBCCCCDDDD
|
111122223333444455556666AAAABBBBCCCCDDDD
|
||||||
uid [ultimate] Alice Engineer <alice@example.org>
|
uid [ultimate] Alice Engineer <alice@example.org>
|
||||||
uid [ultimate] Alice Engineer <allie@example.net>
|
uid [ultimate] Alice Engineer <allie@example.net>
|
||||||
ssb rsa2048 2017-12-06 [E]
|
ssb cv25519 2021-05-01 [E]
|
||||||
ssb rsa2048 2017-12-06 [S]
|
ssb ed25519 2021-05-01 [S]
|
||||||
|
|
||||||
#### Remove the revocation certificate
|
#### Remove the revocation certificate
|
||||||
|
|
||||||
Another file you should remove (but keep in backups) is the revocation
|
Another file you should remove (but keep in backups) is the revocation
|
||||||
certificate that was automatically created with your master key. A revocation
|
certificate that was automatically created with your certification key. A
|
||||||
certificate allows someone to permanently mark your key as revoked, meaning it
|
revocation certificate allows someone to permanently mark your key as revoked,
|
||||||
can no longer be used or trusted for any purpose. You would normally use it to
|
meaning it can no longer be used or trusted for any purpose. You would
|
||||||
revoke a key that, for some reason, you can no longer control -- for example,
|
normally use it to revoke a key that, for some reason, you can no longer
|
||||||
if you had lost the key passphrase.
|
control -- for example, if you had lost the key passphrase.
|
||||||
|
|
||||||
Just as with the master key, if a revocation certificate leaks into malicious
|
Just as with the certification key, if a revocation certificate leaks into
|
||||||
hands, it can be used to destroy your developer digital identity, so it's
|
malicious hands, it can be used to destroy your developer digital identity, so
|
||||||
better to remove it from your home directory.
|
it's better to remove it from your home directory.
|
||||||
|
|
||||||
cd ~/.gnupg/openpgp-revocs.d
|
cd ~/.gnupg/openpgp-revocs.d
|
||||||
rm [fpr].rev
|
rm [fpr].rev
|
||||||
|
@ -781,7 +725,7 @@ better to remove it from your home directory.
|
||||||
|
|
||||||
### Considerations
|
### Considerations
|
||||||
|
|
||||||
Even though the master key is now safe from being leaked or stolen, the
|
Even though the certification key is now safe from being leaked or stolen, the
|
||||||
subkeys are still in your home directory. Anyone who manages to get their
|
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
|
hands on those will be able to decrypt your communication or fake your
|
||||||
signatures (if they know the passphrase). Furthermore, each time a GnuPG
|
signatures (if they know the passphrase). Furthermore, each time a GnuPG
|
||||||
|
@ -826,17 +770,18 @@ features on the internal chip. Here are a few recommendations:
|
||||||
|
|
||||||
- [Nitrokey Start](https://shop.nitrokey.com/shop/product/nitrokey-start-6):
|
- [Nitrokey Start](https://shop.nitrokey.com/shop/product/nitrokey-start-6):
|
||||||
Open hardware and Free Software: one of the cheapest options for GnuPG use,
|
Open hardware and Free Software: one of the cheapest options for GnuPG use,
|
||||||
but with fewest extra security features
|
but with fewest extra security features.
|
||||||
- [Nitrokey Pro](https://shop.nitrokey.com/shop/product/nitrokey-pro-3):
|
- [Nitrokey Pro](https://shop.nitrokey.com/shop/product/nitrokey-pro-3):
|
||||||
Similar to the Nitrokey Start, but is tamper-resistant and offers more
|
Similar to the Nitrokey Start, but is tamper-resistant and offers more
|
||||||
security features (but not U2F, see the Fido U2F section of the guide)
|
security features (but not U2F, see the Fido U2F section of the guide); only
|
||||||
- [Yubikey 4](https://www.yubico.com/product/yubikey-4-series/): Proprietary
|
supports NIST ECC cryptography.
|
||||||
hardware and software, but cheaper than Nitrokey Pro and comes available
|
- [Yubikey](https://www.yubico.com/): Proprietary hardware and software, but
|
||||||
in the USB-C form that is more useful with newer laptops; also offers
|
cheaper than Nitrokey Pro and comes available in the USB-C form that is more
|
||||||
additional security features such as U2F
|
useful with newer laptops; also offers additional security features such as
|
||||||
|
U2F; only supports NIST ECC cryptography.
|
||||||
|
|
||||||
Our recommendation is to pick a device that is capable of both smartcard
|
If you want to use ED25519 subkeys, then your only choice is a Nitrokey Start,
|
||||||
functionality and U2F, which, at the time of writing, means a Yubikey 4.
|
though once Nitrokey 3 Pro is available, it should also be considered.
|
||||||
|
|
||||||
#### Configuring your smartcard device
|
#### Configuring your smartcard device
|
||||||
|
|
||||||
|
@ -894,12 +839,12 @@ the full 40-character fingerprint of your key.
|
||||||
Secret subkeys are available.
|
Secret subkeys are available.
|
||||||
|
|
||||||
pub rsa4096/AAAABBBBCCCCDDDD
|
pub rsa4096/AAAABBBBCCCCDDDD
|
||||||
created: 2017-12-07 expires: 2019-12-07 usage: C
|
created: 2021-05-01 expires: 2023-05-01 usage: C
|
||||||
trust: ultimate validity: ultimate
|
trust: ultimate validity: ultimate
|
||||||
ssb rsa2048/1111222233334444
|
ssb cv25519/1111222233334444
|
||||||
created: 2017-12-07 expires: never usage: E
|
created: 2021-05-01 expires: never usage: E
|
||||||
ssb rsa2048/5555666677778888
|
ssb ed25519/5555666677778888
|
||||||
created: 2017-12-07 expires: never usage: S
|
created: 2021-05-01 expires: never usage: S
|
||||||
[ultimate] (1). Alice Engineer <alice@example.org>
|
[ultimate] (1). Alice Engineer <alice@example.org>
|
||||||
[ultimate] (2) Alice Engineer <allie@example.net>
|
[ultimate] (2) Alice Engineer <allie@example.net>
|
||||||
|
|
||||||
|
@ -917,12 +862,12 @@ typing `key 1` (it's the first one in the listing, our **[E]** subkey):
|
||||||
The output should be subtly different:
|
The output should be subtly different:
|
||||||
|
|
||||||
pub rsa4096/AAAABBBBCCCCDDDD
|
pub rsa4096/AAAABBBBCCCCDDDD
|
||||||
created: 2017-12-07 expires: 2019-12-07 usage: C
|
created: 2021-05-01 expires: 2023-05-01 usage: C
|
||||||
trust: ultimate validity: ultimate
|
trust: ultimate validity: ultimate
|
||||||
ssb* rsa2048/1111222233334444
|
ssb* cv25519/1111222233334444
|
||||||
created: 2017-12-07 expires: never usage: E
|
created: 2021-05-01 expires: never usage: E
|
||||||
ssb rsa2048/5555666677778888
|
ssb ed25519/5555666677778888
|
||||||
created: 2017-12-07 expires: never usage: S
|
created: 2021-05-01 expires: never usage: S
|
||||||
[ultimate] (1). Alice Engineer <alice@example.org>
|
[ultimate] (1). Alice Engineer <alice@example.org>
|
||||||
[ultimate] (2) Alice Engineer <allie@example.net>
|
[ultimate] (2) Alice Engineer <allie@example.net>
|
||||||
|
|
||||||
|
@ -974,12 +919,12 @@ If you perform `--list-secret-keys` now, you will see a subtle difference in
|
||||||
the output:
|
the output:
|
||||||
|
|
||||||
$ gpg --list-secret-keys
|
$ gpg --list-secret-keys
|
||||||
sec# rsa4096 2017-12-06 [C] [expires: 2019-12-06]
|
sec# rsa4096 2021-05-01 [C] [expires: 2023-05-01]
|
||||||
111122223333444455556666AAAABBBBCCCCDDDD
|
111122223333444455556666AAAABBBBCCCCDDDD
|
||||||
uid [ultimate] Alice Engineer <alice@example.org>
|
uid [ultimate] Alice Engineer <alice@example.org>
|
||||||
uid [ultimate] Alice Engineer <allie@example.net>
|
uid [ultimate] Alice Engineer <allie@example.net>
|
||||||
ssb> rsa2048 2017-12-06 [E]
|
ssb> cv25519 2021-05-01 [E]
|
||||||
ssb> rsa2048 2017-12-06 [S]
|
ssb> ed25519 2021-05-01 [S]
|
||||||
|
|
||||||
The `>` in the `ssb>` output indicates that the subkey is only available on
|
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
|
the smartcard. If you go back into your secret keys directory and look at the
|
||||||
|
@ -1013,10 +958,10 @@ your PGP key.
|
||||||
|
|
||||||
In all of the below commands, the `[fpr]` is your key fingerprint.
|
In all of the below commands, the `[fpr]` is your key fingerprint.
|
||||||
|
|
||||||
#### Mounting your master key offline storage
|
#### Mounting your offline storage
|
||||||
|
|
||||||
You will need your master key for any of the operations below, so you will
|
You will need your certification key for any of the operations below, so you
|
||||||
first need to mount your backup offline storage and tell GnuPG to use it.
|
will first need to mount your backup offline storage and tell GnuPG to use it.
|
||||||
First, find out where the media got mounted, e.g. by looking at the output of
|
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
|
the `mount` command. Then, locate the directory with the backup of your GnuPG
|
||||||
directory and tell GnuPG to use that as its home:
|
directory and tell GnuPG to use that as its home:
|
||||||
|
@ -1038,18 +983,18 @@ want to import these changes back into your regular working directory:
|
||||||
|
|
||||||
#### Extending key expiration date
|
#### Extending key expiration date
|
||||||
|
|
||||||
The master key we created has the default expiration date of 2 years from the
|
The certification key we created has the default expiration date of 2 years
|
||||||
date of creation. This is done both for security reasons and to make obsolete
|
from the date of creation. This is done both for security reasons and to make
|
||||||
keys eventually disappear from keyservers.
|
obsolete keys eventually disappear from keyservers.
|
||||||
|
|
||||||
To extend the expiration on your key by a year from current date, just run:
|
To extend the expiration on your key by a year from current date, just run:
|
||||||
|
|
||||||
$ gpg --quick-set-expire [fpr] 1y
|
$ gpg --quick-set-expire [fpr] 1y
|
||||||
|
|
||||||
You can also use a specific date if that is easier to remember (e.g. your
|
You can also use a specific date if that is easier to remember (e.g. your
|
||||||
birthday, January 1st, or Canada Day):
|
birthday, January 1st, or Canada Day, 2030):
|
||||||
|
|
||||||
$ gpg --quick-set-expire [fpr] 2020-07-01
|
$ gpg --quick-set-expire [fpr] 2030-07-01
|
||||||
|
|
||||||
Remember to send the updated key back to keyservers:
|
Remember to send the updated key back to keyservers:
|
||||||
|
|
||||||
|
@ -1080,8 +1025,7 @@ location, but what if someone had managed to trick you?
|
||||||
|
|
||||||
Or what happens if a backdoor is discovered in one of the projects you've
|
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
|
worked on, and the "Author" line in the commit says it was done by you, while
|
||||||
you're pretty sure you had [nothing to do with
|
you're pretty sure you had [nothing to do with it](https://github.com/jayphelps/git-blame-someone-else)?
|
||||||
it](https://github.com/jayphelps/git-blame-someone-else)?
|
|
||||||
|
|
||||||
To address both of these issues, Git introduced PGP integration. Signed tags
|
To address both of these issues, Git introduced PGP integration. Signed tags
|
||||||
prove the repository integrity by assuring that its contents are exactly the
|
prove the repository integrity by assuring that its contents are exactly the
|
||||||
|
@ -1091,7 +1035,7 @@ having access to your PGP keys.
|
||||||
|
|
||||||
### Checklist
|
### Checklist
|
||||||
|
|
||||||
- [ ] Understand signed tags, commits, and pushes _(ESSENTIAL)_
|
- [ ] Understand signed tags, commits _(ESSENTIAL)_
|
||||||
- [ ] Configure git to use your key _(ESSENTIAL)_
|
- [ ] Configure git to use your key _(ESSENTIAL)_
|
||||||
- [ ] Learn how tag signing and verification works _(ESSENTIAL)_
|
- [ ] Learn how tag signing and verification works _(ESSENTIAL)_
|
||||||
- [ ] Configure git to always sign annotated tags _(NICE)_
|
- [ ] Configure git to always sign annotated tags _(NICE)_
|
||||||
|
@ -1102,8 +1046,7 @@ having access to your PGP keys.
|
||||||
### Considerations
|
### Considerations
|
||||||
|
|
||||||
Git implements multiple levels of integration with PGP, first starting with
|
Git implements multiple levels of integration with PGP, first starting with
|
||||||
signed tags, then introducing signed commits, and finally adding support for
|
signed tags, and then introducing signed commits.
|
||||||
signed pushes.
|
|
||||||
|
|
||||||
#### Understanding Git Hashes
|
#### Understanding Git Hashes
|
||||||
|
|
||||||
|
@ -1182,24 +1125,6 @@ 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
|
PGP signatures provide exact same security assurances about the repository and
|
||||||
its entire history.
|
its entire history.
|
||||||
|
|
||||||
#### Signed pushes
|
|
||||||
|
|
||||||
This is included here for completeness' sake, since this functionality needs
|
|
||||||
to be enabled on the server receiving the push before it does anything useful.
|
|
||||||
As we saw above, PGP-signing a git object gives verifiable information about
|
|
||||||
the developer's git tree, but not about their *intent* for that tree.
|
|
||||||
|
|
||||||
For example, you can be working on an experimental branch in your own git fork
|
|
||||||
trying out a promising cool feature, but after you submit your work for
|
|
||||||
review, someone finds a nasty bug in your code. Since your commits are
|
|
||||||
properly signed, someone can take the branch containing your nasty bug and
|
|
||||||
push it into master, introducing a vulnerability that was never intended to go
|
|
||||||
into production. Since the commit is properly signed with your key, everything
|
|
||||||
looks legitimate and your reputation is questioned when the bug is discovered.
|
|
||||||
|
|
||||||
Ability to require PGP-signatures during `git push` was added in order to
|
|
||||||
certify the *intent* of the commit, and not merely verify its contents.
|
|
||||||
|
|
||||||
#### Configure git to use your PGP key
|
#### Configure git to use your PGP key
|
||||||
|
|
||||||
If you only have one secret key in your keyring, then you don't really need to
|
If you only have one secret key in your keyring, then you don't really need to
|
||||||
|
@ -1210,11 +1135,6 @@ key should be used (`[fpr]` is the fingerprint of your key):
|
||||||
|
|
||||||
$ git config --global user.signingKey [fpr]
|
$ git config --global user.signingKey [fpr]
|
||||||
|
|
||||||
**NOTE**: If you have a distinct `gpg2` command, then you should tell git to
|
|
||||||
always use it instead of the legacy `gpg` from version 1:
|
|
||||||
|
|
||||||
$ git config --global gpg.program gpg2
|
|
||||||
|
|
||||||
#### How to work with signed tags
|
#### How to work with signed tags
|
||||||
|
|
||||||
To create a signed tag, simply pass the `-s` switch to the tag command:
|
To create a signed tag, simply pass the `-s` switch to the tag command:
|
||||||
|
@ -1360,18 +1280,12 @@ 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
|
ssh sessions. You just need to tell your environment to use the correct socket
|
||||||
file for talking to the agent.
|
file for talking to the agent.
|
||||||
|
|
||||||
First, add the following to your `~/.gnupg/gpg-agent.conf`:
|
All you need is add this to your `.bashrc`:
|
||||||
|
|
||||||
enable-ssh-support
|
|
||||||
|
|
||||||
Then, add this to your `.bashrc`:
|
|
||||||
|
|
||||||
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
|
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
|
||||||
|
|
||||||
You will need to kill the existing `gpg-agent` process and start a new login
|
Then start a new login session for the changes to take effect:
|
||||||
session for the changes to take effect:
|
|
||||||
|
|
||||||
$ killall gpg-agent
|
|
||||||
$ bash
|
$ bash
|
||||||
$ ssh-add -L
|
$ ssh-add -L
|
||||||
|
|
||||||
|
@ -1500,7 +1414,8 @@ By this point you have accomplished the following important tasks:
|
||||||
|
|
||||||
1. Created your developer identity and protected it using PGP cryptography.
|
1. Created your developer identity and protected it using PGP cryptography.
|
||||||
2. Configured your environment so your identity is not easily stolen by moving
|
2. Configured your environment so your identity is not easily stolen by moving
|
||||||
your master key offline and your subkeys to an external hardware device.
|
your certification key offline and your subkeys to an external hardware
|
||||||
|
device.
|
||||||
3. Configured your git environment to ensure that anyone using your project is
|
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.
|
able to verify the integrity of the repository and its entire history.
|
||||||
4. Secured your online accounts using 2-factor authentication.
|
4. Secured your online accounts using 2-factor authentication.
|
||||||
|
|
Loading…
Reference in a new issue