---
title: "Import GPG Subkeys into a YubiKey While Keeping Them on Your PC"
url: "https://blog.101ta28.com/en/posts/keep-gpg-subkeys-when-moving-to-yubikey/"
language: "en"
description: "Use a temporary GNUPGHOME to import existing signing, authentication, and encryption subkeys into a YubiKey while keeping the GPG secret subkeys on your PC."
---

# Import GPG Subkeys into a YubiKey While Keeping Them on Your PC

> Use a temporary GNUPGHOME to import existing signing, authentication, and encryption subkeys into a YubiKey while keeping the GPG secret subkeys on your PC.

When you use `keytocard` to import GPG secret subkeys into a YubiKey, the secret key material in that GnuPG environment is replaced with references to the card.
To keep the secret subkeys on your PC, copy them into a temporary `GNUPGHOME` and run `keytocard` there.



## The Resulting Key Setup

Before starting, the PC holds the public primary key and three secret subkeys for signing, authentication, and encryption.
The secret primary key is stored only in an offline backup.

Afterward, the PC retains its secret subkeys, and the YubiKey holds the same subkeys.

```text
Offline backup
└─ Secret primary key

PC
├─ Secret signing subkey
├─ Secret authentication subkey
└─ Secret encryption subkey

YubiKey OpenPGP
├─ Signature slot      Secret signing subkey
├─ Authentication slot Secret authentication subkey
└─ Encryption slot     Secret encryption subkey
```

This setup lets you start using a YubiKey without losing the secret subkeys on your PC.

## What `keytocard` Changes

The official GnuPG manual describes `keytocard` as a command that transfers the selected secret key to a smart card.
After a successful transfer and `save`, the secret key material in the active GnuPG environment is replaced with a **card reference stub**.
This stub stores information such as the card's serial number and requests the corresponding card when the secret key is needed.

Running `keytocard` in your usual `~/.gnupg` therefore replaces the secret subkey material in that environment with stubs.
Running it in a temporary `GNUPGHOME` replaces only the temporary environment's secret subkeys, leaving those in your usual environment intact.

Since GnuPG 2.1, `gpg-agent` has managed secret keys and stubs under `private-keys-v1.d`.
The description that secret key material resides only in the traditional secret keyring does not apply to current GnuPG 2.x versions.

## Tested Environment

This article assumes the following environment.

```text
OS: Ubuntu 24.04.4 LTS
GnuPG: 2.4.4
YubiKey: YubiKey 5C NFC
YubiKey firmware: 5.7.4
OpenPGP application: 3.4
Signing subkey: Ed25519
Authentication subkey: Ed25519
Encryption subkey: Curve25519
```

The algorithms supported by the YubiKey 5 OpenPGP application vary by firmware and product family.
According to Yubico's documentation, elliptic-curve cryptography, including Ed25519 and X25519, is supported from firmware 5.2.3 onward.

A YubiKey-related `keytocard` bug in GnuPG 2.4.0 was fixed in 2.4.1.
If you use another version, check its release notes as well.

## Check the Keys and Card First

First, check the GnuPG version and your current secret keys.

```bash
gpg --version
gpg --list-secret-keys \
  --keyid-format LONG \
  --with-subkey-fingerprint
```

Identify the target key by the public primary key's full fingerprint rather than a short key ID.
Set the following variable to that fingerprint, with spaces removed.

```bash
PRIMARY_FINGERPRINT="FULL_FINGERPRINT_OF_YOUR_PUBLIC_PRIMARY_KEY"
```

The markers at the start of entries in the secret key listing also have specific meanings.

- `sec`, `ssb`: usable secret key material is available
- `sec#`, `ssb#`: the corresponding secret key material is unavailable
- `sec>`, `ssb>`: the secret key is on a smart card

Before proceeding, confirm that the secret primary key appears as `sec#` and all three secret subkeys appear as `ssb`.

Connect the YubiKey and check its status as well.

```bash
gpg --card-status
```

Check the following items.

- The card is recognized as an OpenPGP application.
- `Key attributes` match the algorithms of the keys you will import.
- The fingerprints shown for `Signature key`, `Encryption key`, and `Authentication key`.
- You have changed both the User PIN and Admin PIN from their defaults.

Compare the card and PC fingerprints for each purpose, then choose the appropriate next step.

- All three slots are empty: create a temporary environment and proceed with the import.
- All three slots match the PC's subkeys: the desired setup is already complete, so no further import is needed.
- A slot contains a different key, or only some slots match: check the card's purpose and your backups before overwriting anything.

If you overwrite a slot containing an existing key, you cannot recover that secret key from the YubiKey.
Seeing the same fingerprint already listed is not a reason to repeat `keytocard`.

A backup of the secret primary key does not necessarily include the current secret subkeys.
A YubiKey cannot serve as a backup of secret keys, so first verify that you also have an offline backup from which you can restore each S, A, and E secret subkey.

## Create a Temporary GnuPG Environment

Create a temporary directory with `mktemp` and restrict access to its owner.

```bash
umask 077
TEMP_GNUPGHOME="$(mktemp -d)"
chmod 700 "$TEMP_GNUPGHOME"
printf '%s\n' "$TEMP_GNUPGHOME"
```

Leave the `GNUPGHOME` environment variable unchanged and pass `--homedir "$TEMP_GNUPGHOME"` to each command to avoid confusing the temporary and usual environments.

## Copy the Secret Subkeys into the Temporary Environment

Export the secret subkeys from your usual environment and pipe them directly into GnuPG in the temporary environment.

```bash
gpg --export-secret-subkeys "$PRIMARY_FINGERPRINT" |
  gpg --homedir "$TEMP_GNUPGHOME" --import
```

`--export-secret-subkeys` does not mean “export only the specified subkey on its own.”
It outputs a key block that includes the public primary key, replacing only the secret primary key portion with an unusable dummy.
The output contains the secret subkey material, so saving it somewhere unsafe would expose the secret subkeys.

Piping the export directly into the import avoids creating an intermediate file containing secret keys.
The public portion is included, so there is no need to import the public key separately.

Check the result after importing.

```bash
gpg --homedir "$TEMP_GNUPGHOME" \
  --list-secret-keys \
  --keyid-format LONG \
  --with-subkey-fingerprint
```

Confirm that the secret primary key appears as `sec#` and the signing, authentication, and encryption subkeys appear as `ssb`.
Do not proceed to `keytocard` if an unexpected key appears or any required subkey has a `#` or `>` marker.

## Match the YubiKey's Key Attributes

Each YubiKey slot has a key attribute specifying the algorithm of the key it holds.
Skip this section if `gpg --card-status` already shows the following.

```text
Key attributes ...: ed25519 cv25519 ed25519
```

Edit the card only if the slots are empty and the key attributes differ.

```bash
gpg --homedir "$TEMP_GNUPGHOME" --edit-card
```

Enable administrative commands and run `key-attr`.

```text
gpg/card> admin
gpg/card> key-attr
```

You will be prompted to configure Signature, Encryption, and Authentication, in that order.
For all three, choose ECC as the key type and Curve 25519 as the curve.

```text
Signature key:      ed25519
Encryption key:     cv25519
Authentication key: ed25519
```

Exit the card editor after completing the settings.

```text
gpg/card> quit
```

Then display the card status.

```bash
gpg --homedir "$TEMP_GNUPGHOME" --card-status
```

Confirm that `Key attributes` now reads `ed25519 cv25519 ed25519`.
Changing key attributes also writes to the YubiKey itself, so perform this operation only when the slots are empty.

## Import the Secret Subkeys into the YubiKey

Edit the key in the temporary environment.

```bash
gpg --homedir "$TEMP_GNUPGHOME" \
  --edit-key "$PRIMARY_FINGERPRINT"
```

`keytocard` operates on the subkey selected with the `key` command.
Subkey numbers vary between keys, so compare the editor's `usage` and fingerprints with the following table.

| usage | Algorithm  | Destination        |
| :---- | :--------- | :----------------- |
| S     | Ed25519    | Signature key      |
| A     | Ed25519    | Authentication key |
| E     | Curve25519 | Encryption key     |

Select exactly one subkey and use `keytocard` to import it into the corresponding slot.
The selected subkey is marked with `*`.

```text
gpg> key <target subkey number>
gpg> keytocard
```

After importing, use the same `key` command to deselect it, then repeat for the remaining subkeys.

```text
gpg> key <target subkey number>
```

Once all three subkeys have been imported, save the changes.

```text
gpg> save
```

Running `save` replaces each secret subkey's material in the temporary environment with a card reference stub.
These edits are not saved to the secret subkeys in your usual environment.

## Check the Card and Your Usual Environment

First, inspect the YubiKey's slots from the temporary environment.

```bash
gpg --homedir "$TEMP_GNUPGHOME" --card-status
gpg --homedir "$TEMP_GNUPGHOME" \
  --list-secret-keys \
  --keyid-format LONG \
  --with-subkey-fingerprint
```

Confirm that `Signature key`, `Authentication key`, and `Encryption key` show the fingerprints of the corresponding target subkeys.
In the temporary environment's secret key listing, subkeys transferred to the card appear as `ssb>`.

Next, check your usual environment without `--homedir`.

```bash
gpg --list-secret-keys \
  --keyid-format LONG \
  --with-subkey-fingerprint
```

Confirm that each S, A, and E subkey still appears as `ssb` in your usual environment and has not changed to `ssb>`.

## Test Signing and Decryption with the YubiKey

`--card-status` alone does not confirm that the secret keys can be used, so create a signature in the temporary environment.

```bash
printf 'YubiKey signing test\n' > "$TEMP_GNUPGHOME/test.txt"

gpg --homedir "$TEMP_GNUPGHOME" \
  --armor \
  --detach-sign "$TEMP_GNUPGHOME/test.txt"

gpg --homedir "$TEMP_GNUPGHOME" \
  --verify "$TEMP_GNUPGHOME/test.txt.asc" \
  "$TEMP_GNUPGHOME/test.txt"
```

Next, encrypt data with your public key and decrypt it using the YubiKey.

```bash
gpg --homedir "$TEMP_GNUPGHOME" \
  --armor \
  --recipient "$PRIMARY_FINGERPRINT" \
  --output "$TEMP_GNUPGHOME/test.txt.asc.gpg" \
  --encrypt "$TEMP_GNUPGHOME/test.txt"

gpg --homedir "$TEMP_GNUPGHOME" \
  --decrypt "$TEMP_GNUPGHOME/test.txt.asc.gpg"
```

Test the authentication subkey against an actual authentication target, such as SSH.
Configuring `gpg-agent` for SSH is outside the scope of this article.

## Remove the Temporary Environment

After confirming that the card's keys work and the secret subkeys remain in your usual environment, stop the temporary environment's `gpg-agent`.

```bash
gpgconf --homedir "$TEMP_GNUPGHOME" --kill all
```

Confirm that the deletion target is the path created by `mktemp`, then remove the temporary environment.

```bash
case "$TEMP_GNUPGHOME" in
  /tmp/tmp.*) rm -rf -- "$TEMP_GNUPGHOME" ;;
  *) printf 'Unexpected path: %s\n' "$TEMP_GNUPGHOME" >&2 ;;
esac

unset TEMP_GNUPGHOME
unset PRIMARY_FINGERPRINT
```

This deletion does not guarantee physical erasure of data left on an SSD or other storage device.
If your threat model includes recovery after deletion, work in an encrypted temporary filesystem or a disposable environment isolated from the network.

## What Keeping Two Copies of the Same Secret Subkeys Means

Secret keys imported into a YubiKey cannot be exported from the card again as ordinary secret key files.
A YubiKey therefore provides a place to use secret keys, but it is not a backup.

In this setup, the PC also retains the same secret subkeys.
If an attacker compromises the PC and obtains those subkeys, they can sign, authenticate, and decrypt with them without possessing the YubiKey.
Importing the keys into a YubiKey does not provide hardware protection for the secret subkeys on the PC.

The purpose of this setup is to try using a YubiKey without losing the secret subkeys on your PC.
After verifying that everything works and checking your backups, the next step is to decide whether to keep only stubs on the PC or create dedicated YubiKey subkeys in an offline environment.

## References

- [GnuPG Manual: OpenPGP Key Management](https://gnupg.org/documentation/manuals/gnupg/OpenPGP-Key-Management.html)
- [GnuPG Manual: gpg](https://gnupg.org/documentation/manuals/gnupg26/gpg.1.html)
- [GnuPG Manual: gpg-agent](https://gnupg.org/documentation/manuals/gnupg26/gpg-agent.1.html)
- [GnuPG Manual: gpg-card](https://www.gnupg.org/documentation/manuals/gnupg26/gpg-card.1.html)
- [Yubico: OpenPGP Specifics](https://docs.yubico.com/hardware/yubikey/yk-tech-manual/yk5-apps-openpgp.html)
- [Yubico: YubiKey 5.2.3 Enhancements to OpenPGP 3.4](https://developers.yubico.com/PGP/YubiKey_5.2.3_Enhancements_to_OpenPGP_3.4.html)
- [Yubico: Importing keys](https://developers.yubico.com/PGP/Importing_keys.html)
- [GnuPG 2.4.1 release announcement](https://lists.gnupg.org/pipermail/gnupg-users/2023-April/066502.html)
