This commit is contained in:
Heiko Schaefer 2022-06-12 00:04:35 +02:00
parent f393d54092
commit 1ac64f5360
No known key found for this signature in database
GPG key ID: 4A849A1904CCBD7D
6 changed files with 0 additions and 507 deletions

View file

@ -3,7 +3,6 @@
# SPDX-License-Identifier: CC0-1.0
stages:
- pages
- lint
- test
- virtual-test
@ -22,21 +21,6 @@ cache: &general_cache_config
- target/
- $CARGO_HOME
pages:
stage: pages
image: debian:stable-slim
before_script:
- apt update -y -qq
- apt install -y -qq --no-install-recommends wget ca-certificates
- wget https://github.com/rust-lang/mdBook/releases/download/v0.4.15/mdbook-v0.4.15-x86_64-unknown-linux-gnu.tar.gz
- tar xvzf mdbook-v0.4.15-x86_64-unknown-linux-gnu.tar.gz
script:
- ./mdbook build guide/
artifacts:
paths:
- public
cache: [ ]
reuse:
stage: lint
image:

View file

@ -1,16 +0,0 @@
# SPDX-FileCopyrightText: 2022 Heiko Schaefer <heiko@schaefer.name>
# SPDX-License-Identifier: MIT OR Apache-2.0
[book]
authors = ["hkos"]
language = "en"
multilingual = false
src = "src"
title = "OpenPGP card user guide"
[output.html]
git-repository-url = "https://gitlab.com/openpgp-card/openpgp-card"
git-repository-icon = "fa-gitlab"
[build]
build-dir = "../public"

View file

@ -1,12 +0,0 @@
<!--
SPDX-FileCopyrightText: 2022 Heiko Schaefer <heiko@schaefer.name>
SPDX-License-Identifier: MIT OR Apache-2.0
-->
# Summary
- [OpenPGP cards](context.md)
- [Setting up cards with `opgpcard`](opgpcard.md)
- [SSH authentication](ssh.md)
- [git commit signing](git.md)
- [Thunderbird](thunderbird.md)

View file

@ -1,36 +0,0 @@
<!--
SPDX-FileCopyrightText: 2022 Heiko Schaefer <heiko@schaefer.name>
SPDX-License-Identifier: MIT OR Apache-2.0
-->
# OpenPGP card "hardware tokens"
This series of guides describes how to use [OpenPGP card](https://en.wikipedia.org/wiki/OpenPGP_card) "hardware tokens"
(e.g. [YubiKey](https://www.yubico.com/products/), [Nitrokey](https://www.nitrokey.com/)
or [Gnuk](https://www.fsij.org/doc-gnuk/)) with new - and still experimental - Sequoia PGP-based tools.
## What are OpenPGP cards?
OpenPGP cards are hardware tokens that can store private key material and perform cryptographic operations.
The point of using such a device is that private cryptographic key material is never directly accessible to the
user's computer.
This way, even if the user's computer is compromised, their private OpenPGP key material is protected from being
exfiltrated by an attacker.
## Tool support, so far
Until now, most users have interacted with OpenPGP cards using one or both of:
1. [GnuPG](https://www.gnupg.org) (which internally uses a subsystem called [scdaemon](https://www.gnupg.org/documentation/manuals/gnupg/Invoking-SCDAEMON.html)), or
2. [OpenKeychain](https://www.openkeychain.org/) (OpenKeychain can be used via the K9 email software), or the related [TermBot](https://github.com/cotechde/termbot) SSH client, on Android devices.
## New OpenPGP card tools
This series of guides introduces a new set of tools that leverage OpenPGP cards, written in Rust.
These tools are built on a set of [OpenPGP card libraries](https://gitlab.com/openpgp-card/openpgp-card)
and [Sequoia PGP](https://sequoia-pgp.org/).
The ultimate goal of this series is to document a complete suite of easy-to-use tools for all use cases around
OpenPGP cards.

View file

@ -1,286 +0,0 @@
<!--
SPDX-FileCopyrightText: 2022 Heiko Schaefer <heiko@schaefer.name>
SPDX-License-Identifier: MIT OR Apache-2.0
-->
# The opgpcard tool
To set up and inspect OpenPGP cards, we'll use the [`opgpcard`](https://crates.io/crates/openpgp-card-tools) tool,
which is based on [Sequoia PGP](https://sequoia-pgp.org/)
and [new Rust OpenPGP card libraries](https://gitlab.com/openpgp-card/openpgp-card).
## Install
To install the `opgpcard` tool, we
- install the required build dependencies (a Rust toolchain, pcsc-lite, nettle), then
- `cargo install openpgp-card-tools`
[Detailed installation instructions](https://gitlab.com/openpgp-card/openpgp-card/-/tree/main/tools#install).
## Running opgpcard
### Make sure PC/SC is available
`opgpcard` uses the PC/SC framework. So on Linux-based systems, you need to make sure the `pcscd`
service is running to be able to access your OpenPGP cards.
### Troubleshooting "Error: No cards found"
If `opgpcard` unexpectedly prints `Error: No cards found`, your OpenPGP card might be locked by GnuPG.
When you use GnuPG with an OpenPGP card, its `scdaemon` service typically opens your card with exclusive access
privileges, for an indefinite duration. This prevents other software from accessing the card.
To re-gain access to your card, you can:
- mechanically unplug and replug the card, or you can
- tell GnuPG to temporarily shut down its `scdaemon` subsystem (the recommended way to do this is: `gpgconf --kill scdaemon`).
After this, `opgpcard` should be able to access your OpenPGP card.
(Note: With recent versions of GnuPG, you can configure `scdaemon` to
[use PC/SC in shared access mode](https://www.gnupg.org/documentation/manuals/gnupg/Scdaemon-Options.html#index-pcsc_002dshared))
# Exploring the state of an OpenPGP card
Using the `opgpcard` tool, you can easily check the status of a card:
`$ opgpcard status`
The output will start like this:
```
OpenPGP card FFFE:12345678 (card version 2.0)
[...]
```
... and then show information about the keys on the card (if any).
In this case, the card's identifier is `FFFE:12345678`
(you'll need this identifier for your card, in some of the following steps).
# Specifying which card to operate on
`opgpcard` is designed to work just as reliably and easily in environments where many OpenPGP card devices exist,
and are plugged in at the same time. Therefore, you will need to explicitly specify which card you want to operate on,
in many cases.
For read operations `opgpcard` will automatically use that card, when exactly one card is plugged in.
In all other cases:
- when multiple cards are plugged in, and
- for any write operations,
you need to specify which card you want to interact with, via the `--card` (`-c`) parameter.
For example:
`$ opgpcard status -c FFFE:12345678`
## Enumerating all available cards
You can use `opgpcard list` to enumerate all cards that are connected to your system.
# PINs
For some operations, OpenPGP cards require the user to provide a 'PIN', to show that the user is authorized to perform the operation.
Most OpenPGP cards use two different PINs (for different types of operations):
- *User PIN*,
- *Admin PIN*.
The User PIN is required for cryptographic operations, such as decryption or signing with the card.
The Admin PIN is needed to configure the card itself, for example to import a key onto the card.
On new cards (or after a factory reset), the default User PIN is `123456`, the default Admin PIN is `12345678`.
## Modes of PIN entry
`opgpcard` supports three different modes of PIN entry:
1. When the OpenPGP card is inserted in a Smartcard reader with a pinpad, PINs can be entered directly via that pinpad.
2. If no pinpad reader is available, PINs can be entered on the host computer.
3. Alternatively, it's possible to supply PINs via a file (or a file descriptor). This can be convenient in non-interactive settings, like shell scripts.
## Changing your User and Admin PIN from the default values
To change the User PIN from its default of `123456` to a different value (one that third parties can't easily guess),
run:
`$ opgpcard pin -c FFFE:12345678 set-user`
This command will ask you to enter the current User PIN (`123456`, if your card is new), and then a new PIN,
twice (to avoid inadvertently setting the PIN to an unintended value).
Analogously for the Admin PIN, to change it from its default of `12345678`:
`$ opgpcard pin -c FFFE:12345678 set-admin`
The minimum length for User PINs is 6 digits. For the Admin PIN, 8 digits.
(Note that if you lose your Admin PIN, there is no way to recover it! In that case you can start over by blanking the
card with the `factory-reset` command. A `factory-reset` reverts the PINs to their defaults and removes all keys from
the card.)
# Setting metadata on a card
## Set name
You can set a "Cardholder Name" on an OpenPGP card. That name field is informational.
`$ opgpcard admin -c FFFE:12345678 name "Alice Adams"`
## Set URL
You can set a URL on an OpenPGP card.
The URL "should contain a Link to a set of public keys in OpenPGP format, related to the card".
Some software may use this URL to obtain a copy of the corresponding public key for the key material on your card.
`$ opgpcard admin -c FFFE:12345678 url <url>`
If you do use the URL field, the URL should serve a copy of your public key.
For most use cases, you don't need to set this URL.
# Importing a key to a card
*(This operation deletes keys that currently exist on your card.
Make sure your card doesn't contain irreplaceable keys before you import keys!)*
If you have an existing key that you want to import onto your card, you need a file that contains the key
(if you want to use a private key from a GnuPG store, you can export it with `gpg --export-secret-key -a <fingerprint> > key.pgp`).
If you don't have a key yet (or if you prefer to experiment with a test-key, for now), you can generate a new key with
the `sq` utility (available as `sequoia-sq`
in [a number of distributions](https://repology.org/project/sequoia-sq/versions), or you can
[build it as a container, or with the Cargo package manager](https://gitlab.com/sequoia-pgp/sequoia#building-sequoia)).
To generate a basic OpenPGP key, we run:
```
$ sq key generate --export key.pgp
```
We can inspect this newly generated key (or your pre-existing key) by looking at the structure of the OpenPGP key data
in the file:
```
$ sq inspect key.pgp
key.pgp: Transferable Secret Key.
Fingerprint: 17F2509AB619C8D78B598E54567817AC43A7F7AE
Public-key algo: EdDSA Edwards-curve Digital Signature Algorithm
Public-key size: 256 bits
Secret key: Unencrypted
Creation time: 2022-04-20 09:46:27 UTC
Expiration time: 2025-04-20 03:12:48 UTC (creation time + P1095DT62781S)
Key flags: certification
Subkey: E7A3D0E45991BE6445668CFD348634FD4CC638CA
Public-key algo: EdDSA Edwards-curve Digital Signature Algorithm
Public-key size: 256 bits
Secret key: Unencrypted
Creation time: 2022-04-20 09:46:27 UTC
Expiration time: 2025-04-20 03:12:48 UTC (creation time + P1095DT62781S)
Key flags: signing
Subkey: 593970CE20BFE3D58AA4EF12EA988C77EEC05B0A
Public-key algo: ECDH public key algorithm
Public-key size: 256 bits
Secret key: Unencrypted
Creation time: 2022-04-20 09:46:27 UTC
Expiration time: 2025-04-20 03:12:48 UTC (creation time + P1095DT62781S)
Key flags: transport encryption, data-at-rest encryption
```
Here, we see (by looking at the `Key flags` fields) that the primary key `17F2509AB619C8D78B598E54567817AC43A7F7AE`
can be used for certification only. In addition, there is a signing subkey `E7A3D0E45991BE6445668CFD348634FD4CC638CA`
and an encryption subkey `593970CE20BFE3D58AA4EF12EA988C77EEC05B0A`.
## Automatically importing subkeys for simple OpenPGP keys
Because this key has only one (sub)key for signing and encrypting, respectively, we can import it onto our card easily:
```
$ opgpcard admin -c FFFE:12345678 import key.pgp
Enter Admin PIN:
Uploading E7A3D0E45991BE6445668CFD348634FD4CC638CA as signing key
Uploading 593970CE20BFE3D58AA4EF12EA988C77EEC05B0A as decryption key
```
We see that the two subkeys have been loaded into the suitable slots on the card.
For this key, we don't need to explicitly specify the fingerprints of the keys we want to import:
`opgpcard admin import` can automatically import keys that contain exactly one signing (sub)key, and zero or one
decryption and authentication subkeys, respectively.
Checking the card's status now shows:
```
$ opgpcard status
OpenPGP card FFFE:12345678 (card version 2.0)
Signature key
fingerprint: E7A3 D0E4 5991 BE64 4566 8CFD 3486 34FD 4CC6 38CA
created: 2022-04-20 09:46:27
algorithm: Ed25519 (EdDSA)
Decryption key
fingerprint: 5939 70CE 20BF E3D5 8AA4 EF12 EA98 8C77 EEC0 5B0A
created: 2022-04-20 09:46:27
algorithm: Cv25519 (ECDH)
Authentication key
algorithm: RSA 2048 [e 32]
Retry counters: User PIN: 3, Admin PIN: 3, Resetting Code: 3
Signature counter: 0
Signature PIN only valid once: true
```
## Explicitly picking (sub)keys to import, for more complex OpenPGP keys
If our key contains multiple (sub)keys for signing, encrypting, or authentication, respectively,
we need to explicitly specify which subkeys we want imported onto our card.
With the OpenPGP key from above, that would look like:
```
$ opgpcard admin -c FFFE:12345678 import --sig-fp E7A3D0E45991BE6445668CFD348634FD4CC638CA --dec-fp 593970CE20BFE3D58AA4EF12EA988C77EEC05B0A key.pgp
Enter Admin PIN:
Uploading E7A3D0E45991BE6445668CFD348634FD4CC638CA as signing key
Uploading 593970CE20BFE3D58AA4EF12EA988C77EEC05B0A as decryption key
```
# Key generation on a card
*(This operation deletes keys that currently exist on your card.
Make sure your card doesn't contain irreplaceable keys before you generate keys on your card!)*
To generate a new set of ECC Curve 25519 keys on your OpenPGP card, we can run:
`$ opgpcard admin -c FFFE:12345678 generate -o cert.pub 25519`
The output file `cert.pub` will contain the OpenPGP public key that corresponds to the newly generated keys on the card.
## Pros and cons of generating keys on a card
When you generate keys on your card, your computer never has access to the private key material.
This is nice if you want to be sure that the private key material can not possibly get exfiltrated from your computer,
even if it is fully compromised.
On the other hand, this means that you can - by design - not make a backup (or second copy) of these private keys.
If the card is lost (or breaks) these keys are gone forever.
(Also, when generating private key material on a card, you rely on the hard- and software of that card not to have
flaws that may compromise your key's security.)
Depending on your use case, these tradeoffs may or may not be a good fit for your goals.

View file

@ -1,141 +0,0 @@
<!--
SPDX-FileCopyrightText: 2022 Heiko Schaefer <heiko@schaefer.name>
SPDX-License-Identifier: MIT OR Apache-2.0
-->
# SSH login using an OpenPGP card
In this guide, we'll set up OpenPGP card-based SSH logins to a remote machine.
We assume that you have an OpenPGP card plugged into your client machine, and that an authentication key is available
on that card.
We also assume that the `opgpcard` tool [is installed](https://openpgp-card.gitlab.io/openpgp-card/opgpcard.html#install).
## Optional: generate throwaway keys on your card, for this guide
If you have a blank OpenPGP card, and want to generate throwaway keys to try this guide, you can generate keys on the
card by running:
```
$ opgpcard admin -c FFFE:12345678 generate -o /tmp/cert.pub 25519
```
Replace `FFFE:12345678` with the identifier of your own card (as shown by `opgpcard list`).
This command instructs your card to generate a set of ECC Curve 25519 keys. Not all cards support this algorithm.
If yours doesn't, you can generate RSA 2048 keys instead:
```
$ opgpcard admin -c FFFE:12345678 generate -o /tmp/cert.pub rsa2048
```
Key generation will ask for both the Admin PIN (`12345678` by default) and the User PIN (`123456` by default).
You can ignore the public key output in `/tmp/cert.pub`, if you don't want to use these keys outside this guide.
If you only generate keys to try this guide, you'll probably want to run `opgpcard factory-reset -c <identifier>` at
the end. This will revert your card back into a blank state (and remove our throwaway keys).
# Allowing access to the remote server
Now we'll add our "SSH public key" to the remote machine's list of authorized keys.
More specifically, we'll add the SSH public key that corresponds to the authentication key on our OpenPGP card.
This tells the remote machine that we want our OpenPGP card to be considered a valid means of authorization to log in.
## Adding the public key to `authorized_keys` on a remote machine
To see the SSH public key representation of the authentication key on our OpenPGP card, we run `opgpcard ssh`:
```
$ opgpcard ssh
OpenPGP card FFFE:12345678
Authentication key fingerprint:
7A21F955A14C1C134D9EAE90E8B3EFD2581F3113
SSH public key:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP3GtBCzGAUjg8iN9JOo5f+cFCYLaWE8titbIbimtKwe opgpcard:FFFE:12345678
```
In this output, the last line shows our SSH public key, which is:
`ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP3GtBCzGAUjg8iN9JOo5f+cFCYLaWE8titbIbimtKwe opgpcard:FFFE:12345678`
We add this line to the `~/.ssh/authorized_keys` file in an account on a remote server.
Now the SSH daemon on that machine will consider the authentication key on our OpenPGP card as proof that we're allowed
to log in.
(Note that the public key line doesn't need to be kept secret. Only its counterpart, the secret key on our card, is
sensitive.)
# Setting up the client side
Next we install two pieces of software on our client machine, to communicate with the remote machine using
the [SSH authentication protocol](https://datatracker.ietf.org/doc/html/rfc4252) protocol:
1) an OpenPGP card-based private key store daemon, and
2) an ssh-agent implementation.
Each of these will listen to a Unix domain socket (we'll define an environment variable for each).
In this guide, for demonstration purposes, we'll run these services in a terminal, as Rust debug builds, with rather
chatty debug output (in production systems, you'll probably want to run release builds as system services).
NOTE: These services are in an early experimental stage. Read the documentation for caveats, and don't use them
in sensitive contexts, just yet.
## Card-based Private Key Store
This is an experimental Private Key Store that enables use of cryptographic keys stored on OpenPGP cards.
We'll build and run it in place, for this guide:
```
$ git clone https://gitlab.com/sequoia-pgp/pks-openpgp-card
$ cd pks-openpgp-card
$ cargo run -- -H unix://$XDG_RUNTIME_DIR/pks-openpgp-card.sock
```
## Private Key Store-based SSH Agent
An SSH Agent implementation that can use keys on OpenPGP cards, via the Private Key Store from the previous step.
```
$ git clone https://gitlab.com/sequoia-pgp/ssh-agent-pks
$ cd ssh-agent-pks
$ cargo run -- -H unix://$XDG_RUNTIME_DIR/ssh-agent-pks.sock --endpoint $XDG_RUNTIME_DIR/pks-openpgp-card.sock
```
## Using the SSH Agent
To use `ssh-agent-pks` with your system's SSH client, the variable `SSH_AUTH_SOCK` must point to it:
`export SSH_AUTH_SOCK=$XDG_RUNTIME_DIR/ssh-agent-pks.sock`
### Register a card with the agent
Once the two services are running, you can register an OpenPGP card with the `ssh-agent-pks` OpenSSH agent, by telling
it to add the authentication key from the card:
`ssh-add -s /7A21F955A14C1C134D9EAE90E8B3EFD2581F3113`
`7A21F955A14C1C134D9EAE90E8B3EFD2581F3113` is the fingerprint of our authentication key, as shown from
`opgpcard ssh`, above. You need to add the fingerprint of your OpenPGP card's authentication key.
Don't forget to add a slash before the fingerprint!
You will be prompted to "Enter passphrase for PKCS#11" (don't let this message confuse you: you actually need to enter the User PIN for your OpenPGP card, but the SSH software doesn't know this).
Remember that the User PIN is `123456` by default, on most cards (and remember to change the PIN for cards that
you'll use productively).
This operation is not persisting anything on disk, for now. You always need to add keys to `ssh-agent-pks` after
starting it.
## Log into remote machines
When `SSH_AUTH_SOCK` is set, you should now be able to `ssh <remote-machine>`.
This will use the authentication key on your OpenPGP card to authorize your login.
Yay!