1
0
Fork 0
mirror of synced 2024-05-08 14:32:26 +12:00
itpol/developer-security-hygiene.md
Konstantin Ryabitsev a93d12f80a Add more GnuPG bits
Signed-off-by: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
2017-12-06 17:07:14 -05:00

20 KiB

Free software developer security hygiene

Updated: 2017-12-01

Target audience

This document is aimed at developers working on free software projects. It covers the following topics:

  1. Basic introduction to PGP and Git
  2. PGP key best practices
  3. Basic workstation security

We use the term "Free" as in "Freedom," but this guide can also be used for developing non-free or source-available ("Open Source") software. If you write code that goes into public source repositories, you can benefit from getting acquainted with and following this guide.

Topics NOT covered

This is not a "how to write secure software" guide. Please check the resources on secure coding best practices that are available for the programming languages, libraries, and development environments used by your free software project.

Structure

Each section is split into two areas:

  • The checklist that can be adapted to your project's needs
  • Free-form list of considerations that explain what dictated these decisions

Checklist priority levels

The items in each checklist include the priority level, which we hope will help guide your decision:

  • (ESSENTIAL) items should definitely be high on the consideration list. If not implemented, they will introduce high risks to the code that gets committed to the open-source project.
  • (NICE) to have items will improve the overall security, but will affect how you interact with your work environment, and probably require learning new habits or unlearning old ones.
  • (PARANOID) is reserved for items we feel will significantly improve your security, but will require making equally significant adjustments to the way you interact with your operating system.

Remember, these are only guidelines. If you feel these priority levels do not reflect your project's commitment to security, you should adjust them as you see fit.

Basic PGP concepts and tools

Checklist

  • Understand the role of PGP in Free Software Development (ESSENTIAL)
  • Understand the basics of Public Key Cryptography (ESSENTIAL)
  • Understand PGP Encryption vs. Signatures (ESSENTIAL)
  • Understand PGP key identities (ESSENTIAL)
  • Understand PGP key validity (ESSENTIAL)
  • Install GnuPG utilities (version 2.x) (ESSENTIAL)

Considerations

The Free Software community has long relied on PGP for assuring the authenticity and integrity of software products it produced. You may not be aware of it, but whether you are a Linux, Mac or Windows user, you have previously relied on PGP to ensure the integrity of your computing environment:

  • Linux distributions rely on PGP to ensure that binary or source packages have not been altered between when they have been produced and when they are installed by the end-user.
  • Free Software projects usually provide detached PGP signatures to accompany released software archives, so that downstream projects can verify the integrity of downloaded releases before integrating them into their own distributed downloads.
  • Free Software projects routinely rely on PGP signatures within the code itself in order to track provenance and verify integrity of code commits by project developers.

This is very similar to developer certificates/code signing mechanisms used by programmers working on proprietary platforms. In fact, the core concepts behind these two technologies are very much the same -- they differ mostly in the technical aspects of the implementation and the way they delegate trust. PGP does not rely on centralized Certification Authorities, but instead lets each user assign their own trust to each certificate.

Our goal is to get your project on board using PGP for code provenance and integrity tracking, following best practices and observing basic security precautions.

Extremely Basic Overview of PGP operations

You do not need to know the exact details of how PGP works -- understanding the core concepts is enough to be able to use it successfully for our purposes. PGP relies on Public Key Cryptography to convert plain text into encrypted text. This process requires two distinct keys:

  • A public key that is known to everyone
  • A private key that is only known to the owner

Encryption

For encryption, PGP uses the public key of the owner to create a message that is only decryptable using the owner's private key:

  1. the sender generates a random encryption key ("session key")
  2. the sender encrypts the contents using the session key
  3. the sender encrypts the session key using the recipient's public PGP key
  4. the sender sends both the encrypted contents and the encrypted session key to the recipient

To decrypt:

  1. the recipient decrypts the session key using their private PGP key
  2. the recipient uses the session key to decrypt the contents of the message

Signatures

For creating signatures, the private/public PGP keys are used the opposite way:

  1. the signer generates the checksum hash of the contents
  2. the signer uses their own private PGP key to encrypt that checksum
  3. the signer provides the encrypted checksum alongside the contents

To verify the signature:

  1. the verifier generates their own checksum hash of the contents
  2. the verifier uses the signer's public PGP key to decrypt the provided checksum
  3. if the checksums match, the integrity of the contents is verified

Combined usage

Frequently, encrypted messages are also signed with the sender's own PGP key. This should be the default whenever using encrypted messaging, as encryption without authentication is not very meaningful (unless you are a whistleblower or a secret agent).

Understanding Key Identities

Each PGP key must have one or multiple Identities associated with it. Usually, an "Identity" is the person's full name and email address in the following format:

Alice Engineer <alice.engineer@example.com>

Sometimes it will also contain a comment in brackets, to tell the end-user more about that particular key:

Bob Designer (obsolete 1024-bit key) <bob.designer@example.com>

Since people can be associated with multiple professional and personal entities, they can have multiple identities on the same key:

Alice Engineer <alice.engineer@example.com>
Alice Engineer <aengineer@personalmail.example.org>
Alice Engineer <webmaster@girlswhocode.example.net>

When multiple identities are used, one of them would be marked as the "primary identity" to make searching easier.

Understanding Key Validity

To be able to use someone else's public key for encryption or verification, you need to be sure that it actually belongs to the right person (Alice) and not to an impostor (Eve). In PGP, this certainty is called "key validity:"

  • Validity: full -- means we are pretty sure this key belongs to Alice
  • Validity: marginal -- means we are somewhat sure this key belongs to Alice
  • Validity: uknown -- means there is no assurance at all that this key belongs to Alice

Web of Trust (WoT) vs. Trust on First Use (TOFU)

PGP uses 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 certification authorities, PGP leaves this responsibility to each user.

Unfortunately, very few people understand how the Web of Trust works, and even fewer bother to keep it going. It remains an important aspect of the OpenPGP specification, but recent versions of GnuPG (2.2 and above) have implemented an alternative mechanism called "Trust on First Use" (TOFU).

You can think of TOFU as "the SSH-like approach to trust." With SSH, the first time you connect to a remote system, its key fingerprint is recorded and remembered. If the key changes in the future, the SSH client will alert you and refuse to connect, forcing you to make a decision on whether you choose to trust the changed key or not.

Similarly, the first time you import someone's PGP key, it is assumed to be trusted. If at any point in the future GnuPG comes across another key with the same identity, both the previously imported key and the new key will be marked as invalid and you will need to manually figure out which one to trust.

In this guide, we will be using the TOFU trust model.

Installing OpenPGP software

First, it is important to understand the distinction between PGP, OpenPGP, GnuPG and gpg:

  • PGP ("Pretty Good Privacy") is the name of the original commercial software
  • OpenPGP is the IETF standard compatible with the original PGP tool
  • GnuPG ("Gnu Privacy Guard") is free software that implements the OpenPGP standard
  • The command-line tool for GnuPG is called "gpg"

Today, the term "PGP" is almost always used to mean "the OpenPGP standard," not the original commercial software, and therefore "PGP" and "OpenPGP" are interchangeable. The terms "GnuPG" and "gpg" should only be used when referring to the tools, not to the output they produce or OpenPGP features they implement. For example:

  • PGP (not GnuPG or GPG) key
  • PGP (not GnuPG or GPG) signature
  • PGP (not GnuPG or GPG) keyserver

Understanding this should protect you from an inevitable pedantic "actually" from other PGP users you come across.

Installing GnuPG

If you are using Linux, you should already have GnuPG installed. On a Mac, you should install GPG-Suite or you can use brew install gnupg2. For all other platforms, you'll need to do your own research to find the correct places to download and install GnuPG.

GnuPG 1 vs. 2

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 -1

If you see gpg (GnuPG) 1.4.x, then you are using GnuPG v.1. Try the gpg2 command:

gpg2 --version | head -1

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).

Making sure you always use GnuPG2

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 it by setting the alias:

alias gpg='/usr/bin/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

  • Generate the 4096-bit RSA master key (ESSENTIAL)
  • Back up the master key using paperkey (ESSENTIAL)
  • Add all relevant identities (ESSENTIAL)

Considerations

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

In the Free Software world, the [C] key is your digital identity. Once you create the key, you should take extra care to protect it and prevent it from falling into malicious hands.

Before you create the master key

Before you create your master key you need to pick your primary identity and your master passphrase.

Primary identity

An identity is basically in the same format as the From field in emails:

Alice Engineer <alice.engineer@example.org>

You can create new identities and revoke old ones, and you can also change which identity is your "primary" one at a later time. Since the primary identity is shown in all GnuPG operations, you should pick an address/description that is both professional and the most likely one to be used for PGP-enforced communication, such as your work address or the address you use for signing off on project commits.

Passphrase

The passphrase is used exclusively for encrypting the private key with a symmetric algorithm while it is stored on disk. If the contents of your .gnupg directory ever get leaked, a good passphrase is the last line of defense between the thief and them being able to impersonate you online, which is why it is important to set up a good passphrase.

A good guideline for a strong passphrase is 3-4 words from a rich or mixed dictionary that are not quotes from popular sources (songs, books, slogans). You won't need to type the [C] key passphrase very frequently, so it does not need to be easy to type, just easy to remember.

Algorithm and key strength

Even though GnuPG has supported Elliptic Curve crypto for a while now, 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 possible that you will come across tools and hardware devices that will not be able to handle them correctly.

For this reason, we will be generating RSA keys. For our master key, we'll use 4096 bits, and for our subkeys we'll stick to 2048 bits -- it is easy enough to replace subkeys with stronger ones, but the master key must live on for a long time.

Generate the master key

To generate your 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

A dialog will pop up asking to enter the passphrase. Then, you may need to move your mouse around or type on some keys to generate enough entropy until the command completes.

Review the output of the command, it will be something like this:

pub   rsa4096 2017-12-06 [C] [expires: 2019-12-06]
      111122223333444455556666AAAABBBBCCCCDDDD
uid                      Alice Engineer <alice@example.org>

Note the long string on the 2nd line -- that is the full fingerprint of your newly generated key. Key ID can be represented in three different forms:

  • fingerprint, a full 40-character key identifier
  • long, last 16-characters of the fingerprint (AAAABBBBCCCCDDDD)
  • short, last 8 characters of the fingerprint (CCCCDDDD)

You should avoid using 8-character "short key IDs" as they are not sufficiently unique.

At this point, I suggest you open a text editor, copy the fingerprint of your new key and paste it there. You'll need to use it for the next few steps.

Back up your master key

For disaster recovery purposes -- and especially if you intend to use the Web of Trust and collect key signatures from other project developers -- you should create a hardcopy backup of your private key. This is supposed to be a "last resort" measure in case all other backup mechanisms have failed.

The best way to create a printable hardcopy of your private key is using paperkey software written for this very purpose. Paperkey is available on all Linux distros, as well installable via brew install paperkey on Macs.

Run the following command, replacing [fpr] with the full fingerprint of your key:

gpg --export-secret-key [fpr] | paperkey > /tmp/key-backup.txt

The output will be in a format that is easy to OCR or input by hand, should you ever need to recover it. Print out that file, then take a pen and write the key passphrase on the margin of the paper. This is a required step because the key printout is still encrypted with the passphrase, and if you ever change the passphrase on your key, you will not remember what it used to be when you had first created it -- guaranteed.

Put the resulting printout and the hand-written passphrase into an envelope and store in a secure and well-protected place that is away from your home, such as your bank vault.

NOTE ON PRINTERS: Long gone are days when printers were dumb devices connected to the computer's parallel port. These days they have full operating systems, hard drives, and cloud integration. Since the key content we send to the printer will be encrypted with the passphrase, this is a fairly safe operation, but use your best paranoid judgement.

Add relevant identities

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 this for any addresses that you don't expect to use with PGP (e.g. probably not your school alumni address).

The command is (put the full key fingerprint instead of [fpr]):

gpg --quick-add-uid [fpr] 'Alice Engineer <allie@example.net>'

You can review the IDs you've already added using:

gpg --list-key [fpr] | grep ^uid
Pick the primary UID

GnuPG will make the latest UID you add as your primary UID, so if that is different from what you want, you should fix it back:

gpg --quick-set-primary-uid [fpr] 'Alice Engineer <alice@example.org>'

Generating PGP subkeys

Checklist

  • Generate a 2048-bit Encryption key (ESSENTIAL)
  • Generate a 2048-bit Signing key (ESSENTIAL)
  • Generate a 2048-bit Authentication key (NICE)

Considerations

Now that we've created the master key, let's create the keys you'll actually be using for day-to-day work. We create 2048-bit keys because a lot of specialized hardware (we'll discuss this further) does not handle larger keys, 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 fundamental problems with the RSA protocol and longer 4096-bit keys will not make much difference.

Create the Sign and Encrypt subkeys

To create the subkeys, run:

gpg --quick-add-key [fpr] rsa2048 encr
gpg --quick-add-key [fpr] rsa2048 sign

You can also create the Authentication key, which will allow you to use your PGP key for ssh purposes (covered in other guides):

gpg --quick-add-key [fpr] rsa2048 auth

You can review your key information using gpg --list-key [fpr]:

pub   rsa4096 2017-12-06 [C] [expires: 2019-12-06]
      111122223333444455556666AAAABBBBCCCCDDDD
uid           [ultimate] Alice Engineer <alice@example.org>
uid           [ultimate] Alice Engineer <allie@example.net>
sub   rsa2048 2017-12-06 [E]
sub   rsa2048 2017-12-06 [S]

Moving your master key to offline storage

Checklist

  • Prepare encrypted detachable storage (ESSENTIAL)
  • Back up your GnuPG directory (ESSENTIAL)
  • Remove the master key from your home directory (NICE)

Back up your GnuPG directory

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).

This step is especially important if you are going to remove your master key or use smartcard hardware. Do not skip this step!

Prepare detachable encrypted storage

Start by getting a detachable USB drive (preferably two) that you will use for backup purposes. They do not need to be large. You will first need to encrypt them:

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, under Mac it's /Volumes).

Once you know the full mount path, copy your entire GnuPG directory there:

cp -rp $HOME/.gnupg [/media/disk/some/path]/gnupg-backup

You should now test to make sure it still works:

gpg --homedir=[/media/disk/some/path]/gnupg-backup --list-key [fpr]

If you don't get any errors, then you should be good to go. Unmount the USB drive, label it accordingly so you don't blow it away next time you need to use a quick USB drive, and put in a safe place.