요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
Certify primary key와 signing subkey 분리
maintainer-pgp-guide.rst:60-235GnuPG 2.4 이상과 gpg-agent를 사용하고 강한 passphrase를 설정한다. Primary key의 Certify capability는 새 subkey와 identity를 승인하는 root이므로 일상 machine에서 분리하고, 실제 tag·commit signing은 별도 signing subkey로 수행한다.
Certify key는 offline encrypted storage에 복구 가능하게 backup하고 전체 GnuPG directory backup도 검증한다. Backup은 존재만 확인하지 말고 별도 환경에서 key listing과 restore 절차를 test한다.
Certify key 제거와 smartcard
maintainer-pgp-guide.rst:236-572Workstation homedir에는 public primary key와 필요한 subkey만 남기고 Certify private key material을 offline storage로 이동한다. Keygrip와 private-keys-v1.d file을 확인한 뒤 제거하므로 잘못된 file 삭제를 피하고 backup을 먼저 검증한다.
Signing·authentication subkey를 smartcard나 hardware token으로 옮기면 private material이 device 밖으로 나오지 않는다. Device admin PIN, user PIN과 reset code를 안전하게 설정하고 transfer 뒤 local secret stub와 실제 signing을 확인한다.
Smartcard는 backup이 아니다. Device 분실·고장 때 새 subkey를 발급할 수 있도록 offline Certify key와 revoke·rotation 절차가 필요하다.
Expiration 연장과 work directory 갱신
maintainer-pgp-guide.rst:573-638Key expiration을 바꾸려면 offline Certify key를 안전하게 mount하고 subkey expiry를 갱신한 뒤 public key를 다시 배포한다. Workstation keyring과 smartcard stub가 새 metadata를 보는지 확인한다. gpg-agent forwarding over SSH는 remote host가 agent operation을 요청할 수 있다는 trust boundary를 이해하고 제한적으로 사용한다.
Signed tag와 commit
maintainer-pgp-guide.rst:639-765Git user.signingKey와 gpg program을 설정하고 maintainer pull request의 annotated tag를 sign한다. Consumer는 tag object signature, tag가 가리키는 commit과 expected key identity를 모두 확인한다. 단순히 'Good signature'만 보고 key trust를 생략하지 않는다.
Commit signing은 repository policy에 맞게 사용하며 모든 commit을 sign하는 것과 maintainer integration point를 signed tag로 인증하는 목적을 구분한다. git log --show-signature와 verify-tag·verify-commit으로 검증한다.
Patatt signed patch와 key discovery
maintainer-pgp-guide.rst:766-911Patatt는 mail body가 전달 과정에서 유지됐는지 developer signature로 attest한다. 설치·설정 뒤 outgoing patch에 signature header를 넣고 b4·patatt tooling으로 archive message를 검증한다.
WKD와 DANE를 통한 auto key retrieval을 설정할 수 있지만 가져온 key의 identity trust는 별도 문제다. Web of Trust와 TOFU의 차이를 이해하고 kernel.org web-of-trust repository와 직접 확인한 fingerprint를 이용해 maintainer identity를 검증한다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. _pgpguide:
===========================
Kernel Maintainer PGP guide
===========================
:Author: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
This document is aimed at Linux kernel developers, and especially at
subsystem maintainers. It contains a subset of information discussed in
the more general "`Protecting Code Integrity`_" guide published by the
Linux Foundation. Please read that document for more in-depth discussion
on some of the topics mentioned in this guide.
.. _`Protecting Code Integrity`: https://github.com/lfit/itpol/blob/master/protecting-code-integrity.md
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
.. _devs_not_infra:
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 merely
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:
PGP tools
=========
Use GnuPG 2.4 or later
----------------------
Your distro should already have GnuPG installed by default, you just
need to verify that you are using a reasonably recent version of it.
To check, run::
$ gpg --version | head -n1
If you have version 2.4 or above, then you are good to go. If you have
an earlier version, then you are using a release of GnuPG that is no
longer maintained and some commands from this guide may not work.
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. 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
.. note::
It is no longer necessary to start gpg-agent manually at the
beginning of your shell session. You may want to check your rc files
to remove anything you had in place for older versions of GnuPG, as
it may not be doing the right thing any more.
.. _protect_your_key:
Protect your PGP key
====================
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 mentioned earlier 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 PGP Subkeys
-------------------------
A PGP key rarely consists of a single keypair -- usually it is a
collection of independent subkeys that can be used for different
purposes based on their capabilities, assigned at their creation time.
PGP defines four capabilities that a key can have:
- **[S]** keys can be used for signing
- **[E]** keys can be used for encryption
- **[A]** keys can be used for authentication
- **[C]** keys can be used for certifying other keys
The key with the **[C]** capability is often called the "master" key,
but this terminology is misleading because it implies that the Certify
key can be used in place of any of other subkey on the same chain (like
a physical "master key" can be used to open locks made for other keys).
Since this is not the case, this guide will refer to it as "the Certify
key" to avoid any ambiguity.
It is critical to fully understand the following:
1. All subkeys are fully independent from each other. If you lose a
private subkey, it cannot be restored or recreated from any other
private key on your chain.
2. With the exception of the Certify key, there can be multiple subkeys
with identical capabilities (e.g. you can have 2 valid encryption
subkeys, 3 valid signing subkeys, but only one valid certification
subkey). All subkeys are fully independent -- a message encrypted to
one **[E]** subkey cannot be decrypted with any other **[E]** subkey
you may also have.
3. A single subkey may have multiple capabilities (e.g. your **[C]** key
can also be your **[S]** key).
The key carrying the **[C]** (certify) capability 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 web of trust purposes
By default, GnuPG creates the following when generating new keys:
- One subkey 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 ed25519 2022-12-20 [SC] [expires: 2024-12-19]
000000000000000000000000AAAABBBBCCCCDDDD
uid [ultimate] Alice Dev <adev@kernel.org>
ssb cv25519 2022-12-20 [E] [expires: 2024-12-19]
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 Certify key by moving it to offline media,
so if you only have a combined **[SC]** key, then you should create a
separate signing subkey::
$ gpg --quick-addkey [fpr] ed25519 sign
Back up your Certify 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.
A good 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, 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::
The key is still encrypted with your passphrase, so printing out
even to "cloud-integrated" modern printers should remain a
relatively safe operation.
Back up your whole GnuPG directory
----------------------------------
.. warning::
**!!!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 summits.
Start by getting an external media card (preferably two!) that you will
use for backup purposes. You will need to create an encrypted partition
on this device using LUKS -- refer to your distro's documentation on how
to accomplish this.
For the encryption passphrase, you can use the same one as on your
PGP key.
Once the encryption process is over, re-insert your device and make sure
it gets properly mounted. Copy your entire ``.gnupg`` directory over to
the encrypted storage::
$ cp -a ~/.gnupg /media/disk/foo/gnupg-backup
You should now test to make sure everything still works::
$ gpg --homedir=/media/disk/foo/gnupg-backup --list-key [fpr]
If you don't get any errors, then you should be good to go. Unmount the
device, distinctly label it so you don't overwrite it by accident, 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 Certify 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 Certify key from your home directory
and store it on offline storage.
.. warning::
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 Certify key::
$ gpg --with-keygrip --list-key [fpr]
The output will be something like this::
pub ed25519 2022-12-20 [SC] [expires: 2022-12-19]
000000000000000000000000AAAABBBBCCCCDDDD
Keygrip = 1111000000000000000000000000000000000000
uid [ultimate] Alice Dev <adev@kernel.org>
sub cv25519 2022-12-20 [E] [expires: 2022-12-19]
Keygrip = 2222000000000000000000000000000000000000
sub ed25519 2022-12-20 [S]
Keygrip = 3333000000000000000000000000000000000000
Find the keygrip entry that is beneath the ``pub`` line (right under the
Certify 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
It is sufficient to remove the .key file that corresponds to the Certify
key keygrip::
$ cd ~/.gnupg/private-keys-v1.d
$ rm 1111000000000000000000000000000000000000.key
Now, if you issue the ``--list-secret-keys`` command, it will show that
the Certify key is missing (the ``#`` indicates it is not available)::
$ gpg --list-secret-keys
sec# ed25519 2022-12-20 [SC] [expires: 2024-12-19]
000000000000000000000000AAAABBBBCCCCDDDD
uid [ultimate] Alice Dev <adev@kernel.org>
ssb cv25519 2022-12-20 [E] [expires: 2024-12-19]
ssb ed25519 2022-12-20 [S]
You should also remove any ``secring.gpg`` files in the ``~/.gnupg``
directory, which may be left over from previous 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.
.. _smartcards:
Move the subkeys to a dedicated crypto device
=============================================
Even though the Certify 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).
A good 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 media storage device we used earlier for
backup purposes -- while that device is plugged in and mounted, the
operating system is able to access the private key contents.
Using external encrypted 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`_: Open hardware and Free Software, based on FSI
Japan's `Gnuk`_. One of the cheapest options, but offers fewest
security features (such as resistance to tampering or some
side-channel attacks).
- `Nitrokey 3`_: Similar to the Nitrokey Start, but more
tamper-resistant and offers more security features and USB
form-factors. Supports ECC cryptography (ED25519 and NISTP).
- `Yubikey 5`_: proprietary hardware and software, but cheaper than
Nitrokey with a similar set of features. Supports ECC cryptography
(ED25519 and NISTP).
Your choice will depend on cost, shipping availability in your
geographical region, and open/proprietary hardware considerations.
.. note::
If you are listed in MAINTAINERS or have an account at kernel.org,
you `qualify for a free Nitrokey Start`_ courtesy of The Linux
Foundation.
.. _`Nitrokey Start`: https://www.nitrokey.com/products/nitrokeys
.. _`Nitrokey 3`: https://www.nitrokey.com/products/nitrokeys
.. _`Yubikey 5`: https://www.yubico.com/products/yubikey-5-overview/
.. _Gnuk: https://www.fsij.org/doc-gnuk/
.. _`qualify for a free Nitrokey Start`: https://www.kernel.org/nitrokey-digital-tokens-for-kernel-developers.html
Configure 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.
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, gender, login data, etc), but it's not necessary and will
additionally leak information about your smartcard should you lose it.
.. note::
Despite having the name "PIN", neither the user PIN nor the admin
PIN on the card need to be numbers.
.. warning::
Some devices may require that you move the subkeys onto the device
before you can change the passphrase. Please check the documentation
provided by the device manufacturer.
Move 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 ed25519/AAAABBBBCCCCDDDD
created: 2022-12-20 expires: 2024-12-19 usage: SC
trust: ultimate validity: ultimate
ssb cv25519/1111222233334444
created: 2022-12-20 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# ed25519 2022-12-20 [SC] [expires: 2024-12-19]
000000000000000000000000AAAABBBBCCCCDDDD
uid [ultimate] Alice Dev <adev@kernel.org>
ssb> cv25519 2022-12-20 [E] [expires: 2024-12-19]
ssb> ed25519 2022-12-20 [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 safe offline storage
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You will need your Certify 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/foo/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).
Extending key expiration date
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Certify 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] 2038-07-01
Remember to send the updated key back to keyservers::
$ gpg --send-key [fpr]
Updating your work directory after any changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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
Using gpg-agent over ssh
~~~~~~~~~~~~~~~~~~~~~~~~
You can forward your gpg-agent over ssh if you need to sign tags or
commits on a remote system. Please refer to the instructions provided
on the GnuPG wiki:
- `Agent Forwarding over SSH`_
It works more smoothly if you can modify the sshd server settings on the
remote end.
.. _`Agent Forwarding over SSH`: https://wiki.gnupg.org/AgentForwarding
.. _pgp_with_git:
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 malicious code is discovered in the kernel 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`_?
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.
.. _`nothing to do with it`: https://github.com/jayphelps/git-blame-someone-else
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]
How to work with signed tags
----------------------------
To create a signed tag, 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, use the ``verify-tag`` command::
$ git verify-tag [tagname]
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 [...]
If you are verifying someone else's git tag, you will first need to
import their PGP key. Please refer to the ":ref:`verify_identities`"
section below.
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
How to work with signed commits
-------------------------------
It is also possible to create signed commits, but they have limited
usefulness in Linux kernel development. The kernel contribution workflow
relies on sending in patches, and converting commits to patches does not
preserve git commit signatures. Furthermore, when rebasing your own
repository on a newer upstream, PGP commit signatures will end up
discarded. For this reason, most kernel developers don't bother signing
their commits and will ignore signed commits in any external
repositories that they rely upon in their work.
That said, 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.
We recommend this for the following reasons:
1. Should there ever be a need to perform code forensics or track code
provenance, even externally maintained trees carrying PGP commit
signatures will be valuable for such purposes.
2. If you ever need to re-clone your local repository (for example,
after reinstalling your system), this lets you verify the repository
integrity before resuming your work.
3. If someone needs to cherry-pick your commits, this allows them to
quickly verify their integrity before applying them.
Creating signed commits
~~~~~~~~~~~~~~~~~~~~~~~
To create a signed commit, 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
.. note::
Make sure you configure ``gpg-agent`` before you turn this on.
.. _verify_identities:
How to work with signed patches
-------------------------------
It is possible to use your PGP key to sign patches sent to kernel
developer mailing lists. Since existing email signature mechanisms
(PGP-Mime or PGP-inline) tend to cause problems with regular code
review tasks, you should use the tool kernel.org created for this
purpose that puts cryptographic attestation signatures into message
headers (a-la DKIM):
- `Patatt Patch Attestation`_
.. _`Patatt Patch Attestation`: https://pypi.org/project/patatt/
Installing and configuring patatt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. note::
If you use B4 to send in your patches, patatt is already installed
and integrated into your workflow.
Patatt is packaged for many distributions already, so please check there
first. You can also install it from pypi using "``pip install patatt``".
If you already have your PGP key configured with git (via the
``user.signingKey`` configuration parameter), then patatt requires no
further configuration. You can start signing your patches by installing
the git-send-email hook in the repository you want::
patatt install-hook
Now any patches you send with ``git send-email`` will be automatically
signed with your cryptographic signature.
Checking patatt signatures
~~~~~~~~~~~~~~~~~~~~~~~~~~
If you are using ``b4`` to retrieve and apply patches, then it will
automatically attempt to verify all DKIM and patatt signatures it
encounters, for example::
$ b4 am 20220720205013.890942-1-broonie@kernel.org
[...]
Checking attestation on all messages, may take a moment...
---
✓ [PATCH v1 1/3] kselftest/arm64: Correct buffer allocation for SVE Z registers
✓ [PATCH v1 2/3] arm64/sve: Document our actual ABI for clearing registers on syscall
✓ [PATCH v1 3/3] kselftest/arm64: Enforce actual ABI for SVE syscalls
---
✓ Signed: openpgp/broonie@kernel.org
✓ Signed: DKIM/kernel.org
.. note::
Patatt and b4 are still in active development and you should check
the latest documentation for these projects for any new or updated
features.
.. _kernel_identities:
How to verify kernel developer identities
=========================================
Signing tags and commits is straightforward, 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?
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 `add the kernel.org
UID to your key`_ to make WKD more useful to other kernel developers.
.. _`add the kernel.org UID to your key`: https://korg.wiki.kernel.org/userdoc/mail#adding_a_kernelorg_uid_to_your_pgp_key
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 is still an important part 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 for verification
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
Using the kernel.org web of trust repository
--------------------------------------------
Kernel.org maintains a git repository with developers' public keys as a
replacement for replicating keyserver networks that have gone mostly
dark in the past few years. The full documentation for how to set up
that repository as your source of public keys can be found here:
- `Kernel developer PGP Keyring`_
If you are a kernel developer, please consider submitting your key for
inclusion into that keyring.
.. _`Kernel developer PGP Keyring`: https://korg.docs.kernel.org/pgpkeys.html
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Linux 커널 개발에서 PGP의 역할
1-56이 문서는 Linux 커널 개발자, 특히 하위 시스템 maintainer를 위한 PGP 안내서다. Linux Foundation의 Protecting Code Integrity 문서에서 커널 작업에 필요한 부분을 추려 설명하며, 각 주제의 더 깊은 배경은 원문 안내서에서 확인할 수 있다.
PGP의 첫 번째 목적은 커널 개발 공동체가 생산한 코드의 무결성을 보장하는 것이다. 두 번째로 PGP 서명 이메일을 이용해 개발자 사이의 신뢰 가능한 통신 경로를 만드는 데 도움을 준다.
Linux 커널 소스는 분산 Git 저장소와 정기 release tarball의 두 형태로 배포된다. 공식 release를 만드는 개발자는 Git tag에 PGP 서명을 넣고, tarball에는 detached PGP signature를 함께 제공한다. 이 서명은 kernel.org나 mirror에서 받은 내용이 release 개발자의 workstation에 있던 내용과 동일하다는 암호학적 근거가 된다.
2011년 kernel.org 핵심 시스템 침해 이후 Kernel Archives 프로젝트는 인프라의 어느 부분도 언제든 침해될 수 있다고 가정한다. 호스팅 시스템의 보안 수준과 무관하게 신뢰의 종착점은 서버가 아니라 개발자와 개발자의 키여야 한다.
그러나 신뢰 대상을 개발자로 옮기는 것만으로는 사고 책임을 개인에게 전가하는 결과가 될 수 있다. 이 안내서의 목적은 개발자가 안전한 작업 환경을 만들고 커널 무결성을 증명하는 PGP 키를 보호할 수 있도록 구체적인 운용 규칙을 제공하는 것이다.
GnuPG와 gpg-agent
58-104배포판에 기본 설치된 GnuPG의 버전을 먼저 확인한다. 이 문서는 GnuPG 2.4 이상을 기준으로 하며, 더 오래된 release는 유지보수가 끝났고 일부 명령이 동작하지 않을 수 있다.
$ gpg --version | head -n1
gpg-agent는 gpg 명령을 사용할 때 자동으로 시작되어 백그라운드에서 private key passphrase를 cache한다. default-cache-ttl은 마지막 키 사용 뒤 cache가 유지되는 시간이며, 만료 전에 같은 키를 사용하면 countdown이 다시 시작된다. 기본값은 600초다.
max-cache-ttl은 최초 passphrase 입력 이후의 절대 최대 cache 시간이다. 그 사이에 키를 계속 사용했더라도 이 시간이 지나면 다시 passphrase를 입력해야 한다. 기본값은 30분이다.
# ~/.gnupg/gpg-agent.conf
# 일반 TTL 30분, 최대 TTL 2시간
default-cache-ttl 1800
max-cache-ttl 7200
현대 GnuPG에서는 shell session을 시작할 때 gpg-agent를 수동 실행할 필요가 없다. 이전 버전을 위해 rc 파일에 넣어 둔 agent 시작 코드가 있다면 현재 동작과 충돌하지 않는지 확인하고 제거한다.
subkey 구조와 passphrase
106-201이 문서는 이미 커널 개발용 PGP 키가 있다고 가정한다. 키가 없으면 Protecting Code Integrity의 생성 절차를 따르고, 기존 RSA 키가 2048비트보다 약하다면 새 키를 만든다.
PGP key는 보통 하나의 keypair가 아니라 서로 독립된 여러 subkey의 묶음이다. 생성할 때 각 subkey에 capability를 부여한다. [S]는 서명, [E]는 암호화, [A]는 인증, [C]는 다른 키를 인증하는 용도다.
[C] capability를 가진 키를 흔히 master key라고 부르지만, 다른 subkey를 대신할 수 있다는 오해를 부른다. 실제로 [C] 키가 [E] 또는 [S] 키의 private operation을 대신할 수 없으므로 이 문서는 Certify key라고 부른다.
- 각 private subkey는 완전히 독립적이다. 하나를 잃어버리면 같은 key chain의 다른 private key로 복원하거나 다시 만들 수 없다.
- Certify key를 제외하면 같은 capability의 유효한 subkey를 여러 개 둘 수 있다. 한 [E] subkey로 암호화한 메시지를 다른 [E] subkey로 복호화할 수는 없다.
- 하나의 subkey가 여러 capability를 가질 수 있다. 예를 들어 [C]와 [S]를 함께 가진 [SC] 키가 가능하다.
Certify key만 key chain의 관계를 바꿀 수 있다. S/E/A subkey 추가와 폐기, UID 추가·변경·폐기, 자신과 subkey의 만료일 변경, Web of Trust를 위한 다른 사람 키 서명을 수행한다.
GnuPG 기본 생성 결과는 Certify와 Sign을 함께 가진 [SC] key 하나와 별도 [E] subkey 하나다. gpg --list-secret-keys 출력의 sec 아래 긴 40자리 문자열이 fingerprint이며, 아래 명령에서 [fpr]로 표시한 자리에 이 값을 사용한다.
sec ed25519 2022-12-20 [SC] [expires: 2024-12-19]
000000000000000000000000AAAABBBBCCCCDDDD
uid [ultimate] Alice Dev <adev@kernel.org>
ssb cv25519 2022-12-20 [E] [expires: 2024-12-19]
GnuPG는 disk에 저장하는 private key를 passphrase로 암호화한다. .gnupg 디렉터리 전체가 유출되어도 공격자가 passphrase를 얻지 못하면 private key를 바로 사용할 수 없다. 따라서 강한 passphrase는 필수이며 다음 명령으로 설정하거나 바꾼다.
$ gpg --change-passphrase [fpr]
# [SC]만 있다면 독립된 signing subkey 생성
$ gpg --quick-addkey [fpr] ed25519 sign
목표는 Certify key를 offline media로 옮기고 일상 signing 작업에는 별도 [S] subkey를 쓰는 것이다. [SC] 결합 키만 있다면 먼저 signing subkey를 추가한다.
Certify key는 관계와 수명을 관리하고, 일상 작업은 독립 subkey가 맡는다.
Certify key의 종이 재해 복구본
202-235다른 개발자에게 받은 서명이 많을수록 key identity를 잃었을 때의 복구 비용이 커진다. 디지털 저장장치 전체가 손상되는 재해에 대비해 private key의 종이 백업을 만든다.
paperkey는 private key의 핵심 데이터를 출력 가능한 형식으로 만드는 도구다. 형식과 다른 방식보다 나은 점은 man paperkey에서 확인하며, 대부분의 배포판에서 package로 제공한다.
$ gpg --export-secret-key [fpr] | paperkey -o /tmp/key-backup.txt
파일을 출력하고 그 당시의 passphrase를 종이 여백에 손으로 기록하는 것을 강하게 권장한다. 출력된 key material도 passphrase로 암호화되어 있으며, 이후 passphrase를 바꾸면 백업을 만들던 때의 값을 기억하지 못할 가능성이 높다.
출력물과 수기 passphrase를 봉투에 넣어 집과 떨어진 은행 금고 같은 안전한 장소에 둔다. key data가 passphrase로 암호화되어 있으므로 cloud 연동 printer를 통한 출력도 상대적으로 안전하다고 원문은 설명한다.
전체 GnuPG 디렉터리 백업
236-273이 단계는 생략하면 안 된다. 이후 Certify key를 working homedir에서 제거하므로, 검증된 전체 백업이 없으면 key chain을 사용할 수 없게 만들 수 있다.
paperkey는 재해 수준의 최후 복구본이고, 일상적인 key 변경에 사용할 수 있는 외부 백업은 별도로 필요하다. UID 편집, subkey 추가·폐기, 만료일 변경, conference나 summit 뒤 다른 사람 키 서명에는 Certify key가 든 이 복사본을 사용한다.
가급적 두 개의 외부 media를 준비하고 배포판 안내에 따라 LUKS 암호화 partition을 만든다. 암호화 passphrase는 PGP key와 같은 값을 사용할 수 있다고 원문은 제안한다. 장치를 mount한 다음 .gnupg 전체를 속성과 함께 복사한다.
$ cp -a ~/.gnupg /media/disk/foo/gnupg-backup
# 복사본을 직접 사용해 읽기 시험
$ gpg --homedir=/media/disk/foo/gnupg-backup --list-key [fpr]
오류 없이 key가 표시되는지 반드시 시험한다. 장치를 unmount하고 실수로 덮어쓰지 않도록 분명히 표시해 안전한 곳에 보관한다. 다만 Certify 작업 때마다 꺼내야 하므로 재해 복구용 종이보다 접근 가능한 위치여야 한다.
working homedir에서 Certify key 제거
274-353home directory는 새 workstation을 위한 임시 복사, 시스템 관리자의 실수나 악의, 취약한 backup, browser·PDF viewer 같은 desktop app의 malware, 국경 통과 중 강제 조사 등 여러 경로로 유출될 수 있다.
강한 passphrase는 위험을 낮추지만 keylogger, 어깨너머 관찰과 다른 수단으로 노출될 수 있다. 따라서 Certify key는 일상 homedir에서 제거해 offline storage에만 둔다. 이 작업 전에 전체 .gnupg 백업이 정상 동작하는지 다시 확인해야 한다.
먼저 Certify key의 keygrip을 찾는다. 출력에서 pub 줄과 Certify fingerprint 바로 아래에 있는 Keygrip이 대상이다. 각 keygrip은 ~/.gnupg/private-keys-v1.d의 같은 이름 .key 파일에 대응한다.
$ gpg --with-keygrip --list-key [fpr]
pub ed25519 2022-12-20 [SC] [expires: 2022-12-19]
000000000000000000000000AAAABBBBCCCCDDDD
Keygrip = 1111000000000000000000000000000000000000
uid [ultimate] Alice Dev <adev@kernel.org>
sub cv25519 2022-12-20 [E] [expires: 2022-12-19]
Keygrip = 2222000000000000000000000000000000000000
sub ed25519 2022-12-20 [S]
Keygrip = 3333000000000000000000000000000000000000
$ cd ~/.gnupg/private-keys-v1.d
$ ls
1111000000000000000000000000000000000000.key
2222000000000000000000000000000000000000.key
3333000000000000000000000000000000000000.key
# 백업을 검증한 뒤 Certify key 파일만 제거
$ rm 1111000000000000000000000000000000000000.key
이후 gpg --list-secret-keys에서 sec#가 표시되어야 한다. #은 public 정보는 있지만 해당 private key가 현재 homedir에 없다는 뜻이다. [E]와 새 [S] subkey는 ssb로 계속 표시된다.
$ gpg --list-secret-keys
sec# ed25519 2022-12-20 [SC] [expires: 2024-12-19]
000000000000000000000000AAAABBBBCCCCDDDD
uid [ultimate] Alice Dev <adev@kernel.org>
ssb cv25519 2022-12-20 [E] [expires: 2024-12-19]
ssb ed25519 2022-12-20 [S]
이전 GnuPG가 남긴 ~/.gnupg/secring.gpg에도 private key가 들어 있을 수 있으므로 제거한다. private-keys-v1.d가 없다면 아직 GnuPG v1의 legacy secring.gpg를 쓰는 상태다. passphrase 변경이나 subkey 추가 같은 key 변경을 수행하면 새 형식으로 자동 변환되며, 변환과 백업 확인 뒤 obsolete secring.gpg를 삭제한다.
smartcard의 보안 경계와 장치 선택
354-416Certify key를 offline으로 옮겨도 [S]와 [E] subkey가 homedir에 남아 있으면 passphrase를 아는 공격자가 서명을 위조하거나 통신을 복호화할 수 있다. GnuPG operation 때 private key가 system memory에 올라오므로 Meltdown과 Spectre 같은 고급 공격으로 memory에서 탈취될 가능성도 고려해야 한다.
smartcard는 private key를 chip 안에 저장하고 암호 연산을 card 자체에서 수행한다. key 내용이 card 밖으로 나오지 않으므로 연결된 computer OS가 private key 자체를 읽을 수 없다. mount 중인 암호화 외장 media에서는 OS가 private key를 읽을 수 있다는 점과 근본적으로 다르다. 암호화 media는 smartcard의 대체재가 아니다.
| 장치 | 특징 |
|---|---|
| Nitrokey Start | FSI Japan Gnuk 기반 open hardware와 Free Software. 저렴하지만 tamper 및 일부 side-channel 저항 기능은 적음 |
| Nitrokey 3 | Start와 유사하지만 더 강한 tamper 저항, 다양한 USB form factor, ED25519와 NISTP ECC 지원 |
| Yubikey 5 | proprietary hardware/software, 유사 기능의 Nitrokey보다 저렴할 수 있으며 ED25519와 NISTP ECC 지원 |
가격, 지역 배송 가능성, open 또는 proprietary hardware에 대한 요구를 기준으로 선택한다. MAINTAINERS에 등재되었거나 kernel.org 계정이 있는 개발자는 Linux Foundation이 제공하는 무료 Nitrokey Start 대상이 될 수 있다.
암호화 backup과 smartcard는 목적이 다르다. backup은 복구 가능성을, smartcard는 일상 operation 중 key 비노출을 제공한다.
smartcard 설정과 subkey 이전
418-532현대 Linux workstation에서는 smartcard USB 장치를 연결하면 보통 바로 인식된다. gpg --card-status로 card 세부 정보가 표시되는지 확인한다. 인식 실패 원인 분석은 장치와 배포판별 지원 문서를 따른다.
$ gpg --card-status
$ gpg --card-edit
[...omitted...]
gpg/card> admin
Admin commands are allowed
gpg/card> passwd
card menu에서 user PIN(1), Admin PIN(3), Reset Code(4)를 설정하고 안전한 장소에 기록한다. 특히 자주 쓰지 않는 Admin PIN과 card를 완전히 초기화할 수 있는 Reset Code를 잊지 않게 보관해야 한다. 이름, 성별, login data 같은 값은 필수가 아니며 card 분실 시 불필요한 개인정보를 노출할 수 있다. PIN이라는 이름과 달리 숫자만 사용할 필요는 없다.
일부 장치는 passphrase를 바꾸기 전에 subkey를 먼저 장치로 옮겨야 할 수 있으므로 제조사 문서를 확인한다. card menu에서 q로 나가 변경을 저장한 뒤, PGP passphrase와 card Admin PIN을 준비하고 key edit menu를 연다.
$ gpg --edit-key [fpr]
Secret subkeys are available.
pub ed25519/AAAABBBBCCCCDDDD
created: 2022-12-20 expires: 2024-12-19 usage: SC
trust: ultimate validity: ultimate
ssb cv25519/1111222233334444
created: 2022-12-20 expires: never usage: E
ssb ed25519/5555666677778888
created: 2017-12-07 expires: never usage: S
[ultimate] (1). Alice Dev <adev@kernel.org>
gpg>
gpg> menu에서 key 1은 첫 번째 [E] subkey를 선택한다. 출력의 ssb* 별표가 현재 선택된 key를 나타내며 같은 명령을 다시 입력하면 선택이 해제되는 toggle이다. keytocard를 실행하고 Encryption key slot 2를 선택한다. PGP passphrase와 Admin PIN 입력 뒤 오류가 없으면 이전된 것이다.
gpg> key 1
gpg> keytocard
Please select where to store the key:
(2) Encryption key
Your selection? 2
다음 key를 옮기기 전에 key 1을 다시 입력해 [E] 선택을 반드시 해제하고 key 2로 [S]를 선택한다. [S] key를 Signature와 Authentication에 모두 쓸 수 있어도 이 절차에서는 Signature slot 1에 넣는다.
gpg> key 1
gpg> key 2
gpg> keytocard
Please select where to store the key:
(1) Signature key
(3) Authentication key
Your selection? 1
gpg> q
Save changes? (y/N) y
변경을 저장하면 card로 옮긴 private subkey가 homedir에서 삭제된다. 교체 card에 다시 넣어야 할 때는 앞에서 만든 검증된 offline backup을 사용한다.
smartcard 이전 결과 검증
534-571gpg --list-secret-keys를 다시 실행하면 Certify key는 sec#, card의 subkey는 ssb>로 표시된다. >는 private subkey가 smartcard에만 있다는 뜻이다.
$ gpg --list-secret-keys
sec# ed25519 2022-12-20 [SC] [expires: 2024-12-19]
000000000000000000000000AAAABBBBCCCCDDDD
uid [ultimate] Alice Dev <adev@kernel.org>
ssb> cv25519 2022-12-20 [E] [expires: 2024-12-19]
ssb> ed25519 2022-12-20 [S]
private-keys-v1.d의 .key 파일은 실제 key가 아니라 card 위치를 가리키는 stub으로 바뀐다. strings 출력에 shadowed-private-key가 있으면 실제 내용은 smartcard에 있다는 뜻이다.
$ cd ~/.gnupg/private-keys-v1.d
$ strings *.key | grep 'private-key'
실제 서명으로 card 동작을 시험한다. 첫 명령에서 smartcard PIN을 요구하고, verify 결과에 Good signature가 나와야 한다.
$ echo "Hello world" | gpg --clearsign > /tmp/test.asc
$ gpg --verify /tmp/test.asc
offline Certify key 운용
573-635Certify 작업을 시작할 때 암호화된 offline storage를 mount하고 GNUPGHOME을 그 백업 디렉터리로 지정한다. gpg --list-secret-keys에서 sec#가 아니라 sec가 표시되어 실제 Certify private key를 읽고 있는지 확인한다.
$ export GNUPGHOME=/media/disk/foo/gnupg-backup
$ gpg --list-secret-keys
Certify key의 기본 만료 기간은 생성 후 2년이다. 키가 무기한 유효하지 않게 하는 보안 목적과, 사용하지 않는 key가 keyserver에서 결국 사라지게 하는 목적이 있다. 현재 날짜에서 1년 연장하거나 기억하기 쉬운 특정 날짜를 지정할 수 있다.
$ gpg --quick-set-expire [fpr] 1y
$ gpg --quick-set-expire [fpr] 2038-07-01
$ gpg --send-key [fpr]
변경한 public key를 keyserver로 다시 보낸다. offline storage에서 변경한 내용을 평소 working keyring으로 export/import한 뒤 GNUPGHOME을 해제한다.
$ gpg --export | gpg --homedir ~/.gnupg --import
$ unset GNUPGHOME
원격 system에서 tag나 commit을 서명해야 한다면 gpg-agent를 SSH로 forwarding할 수 있다. 원격 sshd 설정을 수정할 수 있을 때 더 원활하며, 구체적인 socket forwarding 절차는 GnuPG wiki를 따른다.
Git 설정과 signed tag
637-716Git 저장소를 clone하면 tag, commit, branch를 포함한 전체 history가 로컬에 생긴다. 여러 곳에 복제된 linux.git 가운데 어떤 사본이 악의적으로 바뀌지 않았는지, commit Author에 자신의 이름을 넣은 코드가 실제 자신이 만든 것인지 확인하려면 별도 암호학적 증거가 필요하다.
signed tag는 그 tag가 가리키는 repository 내용이 tag를 만든 개발자의 workstation과 동일하다는 무결성 기준점을 제공한다. signed commit은 공격자가 private key 없이 개발자를 사칭하기 어렵게 한다.
secret key가 하나뿐이면 기본 key로 선택된다. 여러 key가 있다면 Git이 사용할 fingerprint를 전역 설정한다.
$ git config --global user.signingKey [fpr]
$ git tag -s [tagname]
다른 개발자가 pull할 repository의 변조 여부를 확인할 수 있도록 모든 Git tag에 서명하는 것을 권장한다. tag는 git verify-tag로 직접 검증한다. 다른 fork에서 tag를 pull하면 Git은 merge 과정에서 tip의 signature를 자동 검증하고 결과를 merge message에 넣는다.
$ git verify-tag [tagname]
$ git pull [url] tags/sometag
Merge tag 'sometag' of [url]
[Tag message]
# gpg: Signature made [...]
# gpg: Good signature from [...]
다른 사람의 tag를 검증하려면 먼저 그 개발자의 public key를 가져와 identity를 검증해야 한다. annotated tag를 항상 서명하도록 강제하려면 tag.forceSignAnnotated를 설정한다.
$ git config --global tag.forceSignAnnotated true
signed commit의 용도와 한계
717-763커널 개발 workflow에서는 commit을 patch로 변환해 mailing list로 보내는데, 이 변환은 Git commit signature를 보존하지 않는다. upstream을 기준으로 rebase해도 기존 commit object가 새로 생성되어 서명이 사라진다. 이 때문에 많은 커널 개발자는 commit signing을 필수로 보지 않고 외부 저장소의 signed commit도 workflow 증거로 사용하지 않는다.
그럼에도 kernel.org, infradead.org, ozlabs.org 같은 공개 hosting에 working tree를 제공한다면 모든 commit에 서명할 것을 권장한다. 훗날 code provenance와 forensic 분석이 필요할 때 외부 tree의 signature도 증거가 되며, system 재설치 후 다시 clone한 저장소 무결성을 확인할 수 있고, 다른 사람이 cherry-pick 전에 commit을 빠르게 검증할 수 있다.
# 한 commit 서명: 소문자 -s와 다른 옵션이므로 대문자 -S
$ git commit -S
# 모든 commit 자동 서명
$ git config --global commit.gpgSign true
자동 commit signing을 켜기 전에 gpg-agent의 passphrase cache와 smartcard 동작을 먼저 구성한다.
patch attestation과 patatt
764-823커널 mailing list로 보내는 patch도 PGP key로 서명할 수 있다. PGP-MIME이나 PGP-inline은 일반 code review와 patch 적용을 방해할 수 있으므로, kernel.org가 만든 patatt를 이용해 DKIM과 비슷한 cryptographic attestation을 message header에 넣는다.
B4로 patch를 전송한다면 patatt가 이미 설치되어 workflow에 통합되어 있다. 그 밖에는 배포판 package를 우선 확인하고 필요하면 pip install patatt로 설치한다. Git user.signingKey를 이미 설정했다면 추가 key 설정 없이 repository에 git-send-email hook을 설치할 수 있다.
$ pip install patatt
$ patatt install-hook
이후 git send-email로 보내는 patch에는 자동으로 cryptographic signature가 붙는다. b4로 patch를 가져와 적용하면 발견한 DKIM과 patatt signature를 자동으로 검증한다.
$ b4 am 20220720205013.890942-1-broonie@kernel.org
[...]
Checking attestation on all messages, may take a moment...
---
[PATCH v1 1/3] kselftest/arm64: Correct buffer allocation for SVE Z registers
[PATCH v1 2/3] arm64/sve: Document our actual ABI for clearing registers on syscall
[PATCH v1 3/3] kselftest/arm64: Enforce actual ABI for SVE syscalls
---
Signed: openpgp/broonie@kernel.org
Signed: DKIM/kernel.org
patatt와 b4는 계속 개발되고 있으므로 현재 project 문서에서 새 기능과 변경된 사용법을 확인한다.
WKD와 DANE로 개발자 key 찾기
825-867서명이 수학적으로 유효하다는 사실만으로 그 key가 실제 커널 개발자의 것임을 증명할 수는 없다. 공격자가 같은 이름과 이메일로 새 key를 만들 수 있으므로, public key 획득 경로와 identity binding을 검증해야 한다.
다른 개발자 public key collection이 충분하지 않다면 GnuPG의 자동 발견을 이용할 수 있다. WKD와 DANE는 각각 TLS와 DNSSEC이라는 위임된 신뢰 기술을 통해 public key를 찾고 가져온다.
# ~/.gnupg/gpg.conf
auto-key-locate wkd,dane,local
auto-key-retrieve
DANE는 public key를 DNS에 게시하고 DNSSEC-signed zone으로 보호한다. WKD는 HTTPS 조회를 사용한다. GnuPG는 자동으로 가져온 key를 local keyring에 추가하기 전에 DANE에서는 DNSSEC을, WKD에서는 TLS certificate를 검증한다.
kernel.org는 계정이 있는 모든 개발자의 WKD를 게시한다. 설정 뒤 Linus Torvalds와 Greg Kroah-Hartman의 key를 이메일 주소로 찾을 수 있다. kernel.org 계정이 있다면 자신의 key에 kernel.org UID를 추가해 다른 개발자의 WKD 검색을 돕는다.
$ gpg --locate-keys torvalds@kernel.org gregkh@kernel.org
Web of Trust와 TOFU
869-897PGP의 Web of Trust는 HTTPS/TLS의 중앙 Certification Authority를 대신하려는 분산 trust delegation 방식이다. software vendor가 신뢰할 인증자를 정하는 대신 각 사용자가 누구의 인증을 신뢰할지 결정한다.
Web of Trust의 실제 운용은 이해하기 어렵다. GnuPG 2.2 이상은 대안으로 Trust on First Use를 제공한다. SSH가 첫 연결의 host key fingerprint를 기억하고 이후 변경을 경고하듯, TOFU는 처음 가져온 identity-key 연결을 기록한다.
나중에 같은 identity를 가진 다른 key가 나타나면 기존 key와 새 key를 모두 검증 대상으로 표시하고 사용자가 어느 것을 유지할지 판단하게 한다. 문서는 GnuPG v2의 새 기본값인 TOFU+PGP 결합 trust model을 권장한다.
# ~/.gnupg/gpg.conf
trust-model tofu+pgp
kernel.org 개발자 keyring
898-911기존 복제형 keyserver network가 최근 수년 동안 대부분 제대로 동작하지 않게 되자 kernel.org는 개발자 public key를 모은 Git repository를 운영한다. 이 저장소를 public key source로 구성하는 전체 절차는 Kernel developer PGP Keyring 문서에 있다.
커널 개발자라면 다른 개발자가 자신의 서명을 검증할 수 있도록 해당 keyring에 public key를 제출하는 것을 검토한다.
Developer identity와 release provenance
maintainer-pgp-guide.rst:4-59Kernel workflow에서 PGP는 server나 mail infrastructure 자체보다 특정 developer가 tag, commit 또는 patch를 승인했다는 identity chain을 검증한다. Repository mirror가 여러 곳이어도 signed object와 trusted key를 검증해 maintainer handoff provenance를 확인한다.