Some help with split-gpg2

This is probably a very dumb question but how do you go about actually installing split-gpg2?

I’ve read the docs from here: GitHub - QubesOS/qubes-app-linux-split-gpg2: split-gpg v2

But perhaps I’ve misunderstood but that seems to suggest rebuilding qubes to include it. Whereas a bunch of threads seem to suggest it can just be installed.

I’ve tried various combinations of sudo dnf install split-gpg, split-gpg2, qubes-split-gpg etc and always getting a not found error.

Can someone offer some advice?

1 Like

In your split-gpg2 vault template:

  • Install package split-gpg2
  • Maybe remove qubes-gpg-split if it’s installed (might not be necessary)
  • shutdown

In your split-gpg2 client template:

  • Install package split-gpg2
  • shutdown

Then create (or repurpose) vault and client app qubes that are backed by the templates above.

Then in dom0:

  • Install package split-gpg2-dom0 (edit: not actually necessary)
  • In a new file /etc/qubes/policy.d/30-user-gpg2.policy, add line qubes.Gpg2 + SPLIT_GPG2_CLIENT_QUBE @default allow target=SPLIT_GPG2_VAULT_QUBE but using your app qube names instead of the all-caps names
  • Run: qvm-service --enable SPLIT_GPG2_CLIENT_QUBE split-gpg2-client (but using your client app qube name)

In your split-gpg2 vault app qube (not template):

  • Setup / import your secret key (as in the doc you linked)

In your split-gpg2 client app qube (not template):

  • Import your public key (as in the doc you linked)

I think that covers it all. It’s not trivial to set it all up. You can have multiple client app qubes, in which case you repeat some of the steps above for each.

2 Likes

Thanks.

This is the bit I seem to get stuck at:

sudo dnf install split-gpg2-dom0
Qubes OS Repository for Dom0                    2.9 MB/s | 3.0 kB     00:00    
No match for argument: split-gpg2-dom0
Error: Unable to find a match: split-gpg2-dom0

In dom0 you don’t usually use dnf directly to install packages. Instead you go through qubes-dom0-update:

sudo qubes-dom0-update split-gpg2-dom0
2 Likes

A new documentation page is about to be merged Rewrite Split GPG-2 tutorial by parulin · Pull Request #1514 · QubesOS/qubes-doc · GitHub :slight_smile:

3 Likes

ah. Thanks.

Its been a while since I’ve been using qubes. Have forgotten a lot!

2 Likes

What’s the diff between qubes-gpg-split-dom0 and split-gpg2? I am using
the former one.

I dont think that this step is useful:

1 Like

Making some progress, I think.

Running into this error in the client VM.

qubes-gpg-client-wrapper 
ERROR: Destination domain not defined! Set it with QUBES_GPG_DOMAIN env variable.

Yet in Dom0 I’m seeing:

qvm-service secure-email
key-server-VM  on
split-gpg2          on

The key is showing up when I run gpg -k in the key-server-VM

qubes-gpg-client-wrapper is related to Split GPG 1

Try to follow only the instructions of one version to start somewhere.

My suggestion is that you follow these instructions about Split GPG 2 as I tested them a few days ago.

1 Like

Thanks.
I did follow those instructions, but there are no details relating to how to configure Thunderbird to use this split gpg.

I thought the details for Thunderbird were common to both. My mistake.

1 Like

So, can anyone help with advice how to get split-gpg2 working in Thunderbird?

Are you able to use some basic gpg commands?

Yep, key has been imported into the key server vm.

Am comfortable using gpg, just not sure what to ask it to do!

The last newsletter from alimirjamali mentions some test about Thunderbird. And indeed, there is a test: qubes-app-linux-split-gpg2/tests/test_thunderbird.py at main · QubesOS/qubes-app-linux-split-gpg2 · GitHub

That could help you. You could try to follow the Split GPG-1 docs about Thunderbird without:

  • using /usr/bin/qubes-gpg-client-wrapper (use gpg instead)
  • or setting mail.openpgp.alternative_gpg_path

I don’t use Thunderbird + GPG so I’m just guessing.

It’s now live on the documentation

Out of curiosity I tried to configure Thunderbird with Split GPG-2 and it works. No need to follow Split GPG-1 docs: any how-to about Thunderbird using an external GnuPG will work. Split GPG-2 doesn’t need any extra step!

Refs:

Side note: maybe the whole Thunderbird section could be replaced in the Split GPG-1 page by something like that:

The built-in functionality is more limited currently, including that public keys must live in your work-email qube with Thunderbird rather than your offline work-gpg qube.

Follow any tutorial about smartcards or external GnuPG. The only extra step is to make sure to set mail.openpgp.alternative_gpg_path value to /usr/bin/qubes-gpg-client-wrapper.

1 Like

I’m thinking in this “basic” secure setup for devs and sysadmins:

Diagram of the separation of GPG and SSH private keys and subkeys inside AppVM Server and AppVM Client using Qubes Split GPG-2

├── Policy in dom0 (/etc/qubes/policy.d/30-split-gpg.policy)
│   qubes.Gpg2 * @anyvm vault allow
│
├── Policy in dom0 (/etc/qubes/policy.d/50-ssh.policy)
│    qubes.SshAgent * dev vault ask default_target=vault
│
└── AppVM vault Server (network-isolated)
    │
    ├── GPG Keyring (managed by gpg itself)
    │   ├── [sec#] GPG Email Master Key (certify-only, no passphrase)
    │   │   └── [sec#] GPG Email Subkey (RSA sign only for email)
    │   │       └── Used by email qube via qubes.Gpg2 qrexec
    │   │
    │   └── [sec#] GPG Dev Master Key (certify-only, no passphrase)
    │       └── [sec#] GPG Dev Subkey (RSA sign only for Git commits)
    │           └── Used by dev qube via qubes.Gpg2 qrexec
    │
    └── SSH Agent (via ssh-agent systemd service)
        │
        ├── SSH Key for GitHub/GitLab (id_ed25519_github)
        ├── SSH Key for servers (id_ed25519_server)
        │       └── Used by dev qube via qubes.SshAgent qrexec
        │
        └── KeePassXC (optional, for SSH key management)
            ├── Unlocks SSH agent automatically when database opens
            ├── Stores SSH private keys as attachments
            └── Does NOT manage GPG keys—GPG uses its own keyring

└── AppVM dev Client (networked)
    │   Git → uses qubes-gpg-client-wrapper → qrexec → vault (GPG signing)
    │   SSH client → SSH_AUTH_SOCK forwarded → qrexec → vault (SSH auth)
    │
    └── ~/.gitconfig
        ├── user.signingkey = DEV_SUBKEY_ID
        ├── commit.gpgsign = true
        └── gpg.program = qubes-gpg-client-wrapper

└── AppVM email Client (networked)
    │   Thunderbird/Evolution → uses qubes-gpg-client-wrapper → qrexec → vault (GPG signing/decrypt)
    │
    └── Enigmail/Thunderbird config
        ├── GnuPG binary: /usr/bin/qubes-gpg-client-wrapper
        └── Uses same GPG Email Subkey from vault for signing/encryption

Simplified:

appvm-vault (network-isolated)
│
├── GPG Email Master Key (certify-only)
│   └── GPG Email Subkey (sign/encrypt)
│
├── GPG Dev Master Key (certify-only)
│   └── GPG Git Subkey (sign commits)
│
└── SSH Keys (for dev)
    ├── SSH GitHub Key
    └── SSH Server Key

appvm-dev (networked)
├── Git commits (signed with GPG Git Subkey from vault)
└── SSH connections (authenticated with SSH keys from vault)

appvm-email (networked)
└── Thunderbird/Evolution (uses GPG Email Subkey from vault)

What about a key and subkey generator like this?

split-gpg2-key-generator.sh

#!/usr/bin/env bash

# Qubes OS Split GPG-2 key and subkeys generator without passphrase
NAME="Your Name"
EMAIL="your.email@example.com"
COMMENT="Split GPG-2 Key"  # Optional
KEY_EXPIRE="2y"  # Master key expiration
SUBKEY_EXPIRE="1y"  # Subkeys expiration

# Clean start
mv ~/.gnupg ~/.gnupg.backup.$(date +%Y%m%d_%H%M%S)
rm -rf ~/.gnupg
mkdir -m 0700 ~/.gnupg

# Generate master key with expiration
gpg --batch --pinentry-mode loopback --passphrase '' --quick-gen-key "$NAME ($COMMENT) <$EMAIL>" ed25519 sign "$KEY_EXPIRE"

# Get key ID and fingerprint
KEYID=$(gpg --list-secret-keys --keyid-format LONG "$EMAIL" | grep sec | head -1 | awk '{print $2}' | cut -d'/' -f2)
FPR=$(gpg --list-secret-keys --with-colons "$EMAIL" | grep fpr | head -1 | cut -d: -f10)

echo "  Master key created: $KEYID"
echo "  Fingerprint:        $FPR"

# Add signing subkey with expiration
gpg --batch --pinentry-mode loopback --passphrase '' --quick-add-key "$FPR" ed25519 sign "$SUBKEY_EXPIRE"

# Add encryption subkey with expiration
gpg --batch --pinentry-mode loopback --passphrase '' --quick-add-key "$FPR" cv25519 encr "$SUBKEY_EXPIRE"

# Export keys
cd ~/.gnupg
gpg --armor --export "$EMAIL" > "public-key-$KEYID.asc"
gpg --armor --export-secret-keys "$EMAIL" > "master-secret-key-$KEYID.asc"
gpg --armor --export-secret-subkeys "$EMAIL" > "subkeys-only-$KEYID.asc"

# Create revocation certificate
echo "Generating revocation certificate..."
gpg --batch --pinentry-mode loopback --passphrase '' --gen-revoke --armor "$EMAIL" > "revocation-cert-$KEYID.asc" 2>/dev/null <<EOF
y
0
Key has been compromised
y
EOF

# Export ownertrust
gpg --export-ownertrust > "ownertrust-export.txt"

# Test
echo "Testing encryption..."
echo "test" | gpg --batch --yes --always-trust -e -a -r "$EMAIL" | gpg --batch --yes -d 2>/dev/null && echo "Encryption test passed!"

Does it have a good source of entropy?