Split GPG-2
Qubes OS allows you to split the management and usage of GPG keys. You can store your secret keys in one trusted qube and use them in another less trusted qube.
This way the compromise of your less trusted qube does not allow the attacker to automatically also steal all your keys.
How-to split your GPG keys between two qubes
The following how-to will setup Split GPG-2 with two qubes:
one qube holding the private keys, called server-qube. This qube is offline and should be trusted.
the other qube using the keys, called client-qube. This qube doesn’t have to be trusted as much as the server.
Each time you want to do something with a GPG key, the client-qube will delegate the operation to the server-qube. This qube will ask you to confirm the operation.
Install Split GPG-2
In the template(s) qube(s) used by server-qube and client-qube, install the split-gpg2 package.
Note
If you use a minimal template, make sure to install zenity
Create a policy for Split GPG-2
In dom0, create or edit a RPC policy. Add a line like the following and make sure to replace client-qube
and server-qube
by the appropriate values.
qubes.Gpg2 + client-qube @default allow target=server-qube
Generate or import the secret keys in the server qube
In server-qube, you have two options:
either generate your secret keys, like this:
[user@server-qube] $ gpg --gen-key
or, if you want to use some old keys, previously generated in an other qube, import them and the ownertrust. Make sure to replace
/home/user/QubesIncoming/<SOME_OTHER_QUBE>/[...]
by the path of the expected file:[user@server-qube] $ gpg --import /home/user/QubesIncoming/<SOME_OTHER_QUBE>/secret-keys-export [user@server-qube] $ gpg --import-ownertrust /home/user/QubesIncoming/<SOME_OTHER_QUBE>/ownertrust-export
In both situations, you have to export the public part of your keys and the “ownertrust” values in the client qube:
[user@server-qube] $ gpg --export > public-keys-export
[user@server-qube] $ gpg --export-ownertrust > ownertrust-export
[user@server-qube] $ qvm-copy public-keys-export ownertrust-export
Warning
do not export the private keys !
Set up the client qube
Enable split-gpg2-client
service in client qube
The first step is to enable the qube service called split-gpg2-client
.
Import the public keys and ownertrust
If you have previously exported the public keys and the “ownertrust” values from server-qube. Now, you have to import them in the client qube. Replace the following paths by the correct values.
[user@client-qube] $ gpg --import /home/user/QubesIncoming/server-qube/public-keys-export
[user@client-qube] $ gpg --import-ownertrust /home/user/QubesIncoming/server-qube/ownertrust-export
Check that Split GPG-2 works
You should be able to run gpg -K
in the client qube:
[user@client-qube] $ gpg -K
/home/user/.gnupg/pubring.kbx
-----------------------------
sec# rsa2048 2019-12-18 [SC] [expires: 2021-12-17]
50C2035AF57B98CD6E4010F1B808E4BB07BA9EFB
uid [ultimate] test
ssb# rsa2048 2019-12-18 [E]
Troubleshooting
gpg-agent
only shows the “keygrip”
If you have a passphrase on your keys and gpg-agent
only shows the “keygrip” (something like the fingerprint of the private key) when asking for the passphrase, then make sure that you have imported the public key part in the server domain.
Subkeys vs primary keys
Split GPG-2 only knows a hash of the data being signed. Therefore, it cannot differentiate between e.g. signatures of a piece of data or signatures of another key. This means that a client can use Split GPG-2 to sign other keys, which Split GPG did not allow.
To prevent this, Split GPG-2 creates a new GnuPG home directory and imports the secret subkeys (not the primary key!) to it. Clients will be able to use the secret parts of the subkeys, but not of the primary key. If your primary key is able to sign data and certify other keys, and your only subkey can only perform encryption, this means that all signing will fail. To make signing work again, generate a subkey that is capable of signing but not certification. Split GPG-2 does not generate this key for you, so you need to generate it yourself. If you want to generate a key in software, use the addkey
command of gpg2 --edit-key
. If you want to generate a key on a smartcard or other hardware token, use addcardkey
instead. You will need to import your public keys again.
Server options
If you want change some server option, copy /usr/share/doc/split-gpg2/examples/qubes-split-gpg2.conf.example
to /home/user/.config/qubes-split-gpg2/qubes-split-gpg2.conf
and change it as desired, it will take precedence over other loaded files, such as the drop-in configuration files with the suffix .conf
in /home/user/.config/qubes-split-gpg2/conf.d/.
By setting up some values in the configuration file, you can change some parameters. The configurations files are INI files, you can set global options in the DEFAULT
section, or provide some client specific options in their own client:QUBE_NAME
section (where QUBE_NAME
is the name of the client). The following configuration is an example where no qube is automatically accepted besides personal qube:
[DEFAULT]
autoaccept = no
[client:personal]
autoaccept = yes
- autoaccept
- Type:
text
- Default:
no
- Allowed values:
no
,yes
or any integer
By default, all requests made to the server-qube need to be confirmed. You can tell Split GPG-2 to accept requests: never (
no
), always (yes
) or during a period of time after a successful request. To accept all requests following a successful one during one minute, use a value of60
seconds.
This option has two alternatives:
- pksign_autoaccept
- Type:
boolean or integer
- Default:
no
- Allowed values:
no
,yes
or any integer
same as
autoaccept
but only for signing requests
- pkdecrypt_autoaccept
- Type:
boolean or integer
- Default:
no
- Allowed values:
no
,yes
or any integer
same as
autoaccept
but only for decrypt requests
- verbose_notifications
- Type:
boolean
- Default:
no
- Allowed values:
no
oryes
Setting
verbose_notifications
toyes
will provide more notifications.
- allow_keygen
- Type:
boolean
- Default:
no
- Allowed values:
no
oryes
Warning
This feature is new and not much tested. Therefore it’s not security supported!
By setting
allow_keygen
toyes
, you can allow the client to generate new keys. Normal usage should not need this.
- gnupghome
- Type:
full path
- Default:
empty
You can set up a different GnuPG home from the default
/home/user/gpg-home
, usinggnupghome
.
- isolated_gnupghome
- Type:
full path
- Default:
empty
If you store different keys for different client qubes in the same server qube, you can isolate each GnuPG home, by setting
isolated_gnupghome
. The value points at a directory where each client will get its own subdirectory. For example, when this option is set to/home/user/gpg-home
, then the qube personal will use/home/user/gpg-home/personal
as GnuPG home.If you do this, don’t forget to use the option
--gnupg-home
or the environment variableGNUPGHOME
when using gpg commands.
- debug_log
- Type:
path
- Default:
empty
Enable debug logging and set the debug log path.
Warning
This is for debugging purpose only, everything will be logged including potentially confidential data/keys/etc
Notes about Split GPG-2

Example of the Split GPG-2 architecture
In a qube called work-email (with a green level of trust), qubes-gpg-client
pretends to be a standard /usr/bin/gpg
to other apps, here with Thunderbird.
In the work-email qube, qubes-gpg-client
is communicating with qubes-gpg-server
located in the work-gpg qube (with a black level of trust). The communication is made through the qubes.Gpg2
remote procedure call using the qrexec
protocol.
Inside the work-gpg qube, qubes-gpg-server
has access to the GPG key, through /usr/bin/gpg
.
Using Split GPG-2 with Split GPG-1
Using Split GPG-2 as the “backend” for Split GPG is known to work.
Advanced usage: checking what is signed, etc.
Similar to a smartcard, Split GPG-2 only tries to protect the private key. For advanced usages, consider if a specialized RPC service would be better. It could do things like checking what data is signed, detailed logging, exposing the encrypted content only to a VM without network, etc.
Advantages of Split GPG vs. traditional GPG with a smart card
It is often thought that the use of smart cards for private key storage guarantees ultimate safety. While this might be true (unless the attacker can find a usually-very-expensive-and-requiring-physical-presence way to extract the key from the smart card) but only with regards to the safety of the private key itself. However, there is usually nothing that could stop the attacker from requesting the smart card to perform decryption of all the user documents the attacker has found or need to decrypt. In other words, while protecting the user’s private key is an important task, we should not forget that ultimately it is the user data that are to be protected and that the smart card chip has no way of knowing the requests to decrypt documents are now coming from the attacker’s script and not from the user sitting in front of the monitor. (Similarly the smart card doesn’t make the process of digitally signing a document or a transaction in any way more secure – the user cannot know what the chip is really signing. Unfortunately this problem of signing reliability is not solvable by Split GPG.)
With Qubes Split GPG-2 this problem is drastically minimized, because each time the key is to be used the user is asked for consent (with a definable time out, 5 minutes by default), plus is always notified each time the key is used via a tray notification from the domain where GPG backend is running. This way it would be easy to spot unexpected requests to decrypt documents.