feat: add pinentry and gpgme to sys-pgp formula

GPGME can be relevant for client applications such as Thunderbird.
Pinentry can be relevant for the server side, but it is way less tested
in split-gpg2 and discouraged to be used.

For: https://github.com/ben-grande/qusal/issues/83
This commit is contained in:
Ben Grande 2025-01-08 16:48:04 +01:00
parent 31a606e752
commit b03ceb500c
No known key found for this signature in database
GPG Key ID: 00C64E14F51F9E56
14 changed files with 310 additions and 6 deletions

View File

@ -43,6 +43,7 @@ host:
- rpm_spec/qusal-sys-gui-vnc.spec
- rpm_spec/qusal-sys-mirage-firewall.spec
- rpm_spec/qusal-sys-net.spec
- rpm_spec/qusal-sys-pgp.spec
- rpm_spec/qusal-sys-pihole.spec
- rpm_spec/qusal-sys-print.spec
- rpm_spec/qusal-sys-rsync.spec

View File

@ -6,8 +6,16 @@ PGP operations through Qrexec in Qubes OS.
* [Description](#description)
* [Installation](#installation)
* [Passphrase](#passphrase)
* [Client API libraries](#client-api-libraries)
* [Access Control](#access-control)
* [Usage](#usage)
* [Service activation](#service-activation)
* [Key management on the server](#key-management-on-the-server)
* [Passphrase protection](#passphrase-protection)
* [Generate new keys](#generate-new-keys)
* [Import existing keys](#import-existing-keys)
* [Split key usage on the client](#split-key-usage-on-the-client)
## Description
@ -51,6 +59,45 @@ The client qube requires the split GPG client service to be enabled:
qvm-features QUBE service.split-gpg2-client 1
```
### Passphrase
In case you plan to use passphrase, install a GUI pinentry:
```sh
sudo qubesctl --skip-dom0 --targets=tpl-sys-pgp state.apply sys-pgp.install-pinentry
```
### Client API libraries
If you are using an application that interacts using the GnuPG API instead of
the command-line such as Thunderbird, you will need to install on the client
a GPGME package specific to your client application. This is not covered by
default.
Install GPGME C API library on the client template:
```sh
sudo qubesctl --skip-dom0 --targets=tpl-qubes-builder,tpl-dev state.apply sys-pgp.install-client-gpgme-c
```
Install GPGME C++ API library on the client template:
```sh
sudo qubesctl --skip-dom0 --targets=tpl-qubes-builder,tpl-dev state.apply sys-pgp.install-client-gpgme-c++
```
Install GPGME Qt API library on the client template:
```sh
sudo qubesctl --skip-dom0 --targets=tpl-qubes-builder,tpl-dev state.apply sys-pgp.install-client-gpgme-qt
```
Install GPGME Python API library on the client template:
```sh
sudo qubesctl --skip-dom0 --targets=tpl-qubes-builder,tpl-dev state.apply sys-pgp.install-client-gpgme-python
```
## Access Control
_Default policy_: `any qube` can `ask` via the `@default` target if you allow
@ -69,8 +116,10 @@ qubes.Gpg2 * @anyvm @anyvm deny
Consult [upstream documentation](https://github.com/QubesOS/qubes-app-linux-split-gpg2)
on how to use split-gpg2.
Save your PGP keys to `sys-pgp`, using isolated GnuPG home directory per qube
at `~/.gnupg/split-gpg/<QUBE>`.
On the following examples, we will consider `dev` as the client qube and
`ben` as the key user ID.
### Service activation
On `dom0`, enabled the service `split-gpg2-client` for the client qube `dev`:
@ -78,7 +127,49 @@ On `dom0`, enabled the service `split-gpg2-client` for the client qube `dev`:
qvm-features dev service.split-gpg2-client 1
```
On the qube `sys-pgp`, generate or import keys for the client qube `dev`:
### Key management on the server
#### Passphrase protection
Save your PGP keys to `sys-pgp`, using isolated GnuPG home directory per qube
at `~/.gnupg/split-gpg/<QUBE>`.
Please note that adding a passphrase brings
[no additional value](https://www.qubes-os.org/doc/split-gpg):
> Having a passphrase on the key is of little value. An adversary who is
> capable of stealing the key from your vault would almost certainly also be
> capable of stealing the passphrase as you enter it. An adversary who
> obtains the passphrase can then use it in order to change or remove the
> passphrase from the key.
Generate a private keys without a passphrase, use the following when
generating a key pair: `--pinentry-mode loopback --passphrase ""`
If you have already set a passphrase for your private key, you can delete it
by providing the current passphrase to unlock the key, confirming and then
clicking `OK` with an empty passphrase (the dialog might appear twice):
```sh
gpg --homedir ~/.gnupg/split-gpg/dev --edit-key ben passwd
```
#### Generate new keys
You should use subkeys, but configuring this key type is for advanced users
and out of scope for this document. Please refer to an external source.
On the qube `sys-pgp`, generate keys for the client qube `dev`:
```sh
mkdir -p -- ~/.gnupg/split-gpg/dev
gpg --homedir ~/.gnupg/split-gpg/dev --pinentry-mode loopback --passphrase "" --gen-key
gpg --homedir ~/.gnupg/split-gpg/dev --list-secret-keys
```
#### Import existing keys
On the qube `sys-pgp`, import keys for the client qube `dev`:
```sh
mkdir -p -- ~/.gnupg/split-gpg/dev
@ -86,8 +177,16 @@ gpg --homedir ~/.gnupg/split-gpg/dev --import /path/to/secret.key
gpg --homedir ~/.gnupg/split-gpg/dev --list-secret-keys
```
On the qube `dev`, import the public part of your key:
### Split key usage on the client
On the client qube `dev`, import the public part of your key:
```sh
gpg --import /path/to/public.key
```
You should now have access to see the secret keys fingerprints:
```sh
gpg --list-secret-keys
```

View File

@ -0,0 +1,30 @@
{#
SPDX-FileCopyrightText: 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
{% if grains['nodename'] != 'dom0' -%}
include:
- utils.tools.common.update
{% set pkg = {
'Debian': {
'pkg': ['libgpgmepp6'],
},
'RedHat': {
'pkg': ['gpgmepp'],
},
}.get(grains.os_family) -%}
"{{ slsdotpath }}-client-installed-os-specific-gpgme-c++":
pkg.installed:
- require:
- sls: utils.tools.common.update
- install_recommends: False
- skip_suggestions: True
- setopt: "install_weak_deps=False"
- pkgs: {{ pkg.pkg|sequence|yaml }}
{% endif -%}

View File

@ -0,0 +1,10 @@
{#
SPDX-FileCopyrightText: 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
base:
'*':
- match: list
- sys-pgp.install-client-gpgme-c++

View File

@ -0,0 +1,30 @@
{#
SPDX-FileCopyrightText: 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
{% if grains['nodename'] != 'dom0' -%}
include:
- utils.tools.common.update
{% set pkg = {
'Debian': {
'pkg': ['libgpgme11'],
},
'RedHat': {
'pkg': ['gpgme'],
},
}.get(grains.os_family) -%}
"{{ slsdotpath }}-client-installed-os-specific-gpgme-c":
pkg.installed:
- require:
- sls: utils.tools.common.update
- install_recommends: False
- skip_suggestions: True
- setopt: "install_weak_deps=False"
- pkgs: {{ pkg.pkg|sequence|yaml }}
{% endif -%}

View File

@ -0,0 +1,10 @@
{#
SPDX-FileCopyrightText: 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
base:
'*':
- match: list
- sys-pgp.install-client-gpgme-c

View File

@ -0,0 +1,30 @@
{#
SPDX-FileCopyrightText: 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
{% if grains['nodename'] != 'dom0' -%}
include:
- utils.tools.common.update
{% set pkg = {
'Debian': {
'pkg': ['python3-gpg'],
},
'RedHat': {
'pkg': ['python3-gpg'],
},
}.get(grains.os_family) -%}
"{{ slsdotpath }}-client-installed-os-specific-gpgme-python":
pkg.installed:
- require:
- sls: utils.tools.common.update
- install_recommends: False
- skip_suggestions: True
- setopt: "install_weak_deps=False"
- pkgs: {{ pkg.pkg|sequence|yaml }}
{% endif -%}

View File

@ -0,0 +1,10 @@
{#
SPDX-FileCopyrightText: 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
base:
'*':
- match: list
- sys-pgp.install-client-python

View File

@ -0,0 +1,35 @@
{#
SPDX-FileCopyrightText: 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
{% if grains['nodename'] != 'dom0' -%}
include:
- utils.tools.common.update
{% set pkg = {
'Debian': {
'pkg': ['libqgpgme15'],
},
'RedHat': {
'pkg':
{% if grains.os == 'Fedora' and grains.osmajorrelease | int >= 40 %}
['qgpgme-qt5', 'qgpgme-qt6'],
{% else %}
['qgpgme'],
{% endif %}
},
}.get(grains.os_family) -%}
"{{ slsdotpath }}-client-installed-os-specific-gpgme-qt":
pkg.installed:
- require:
- sls: utils.tools.common.update
- install_recommends: False
- skip_suggestions: True
- setopt: "install_weak_deps=False"
- pkgs: {{ pkg.pkg|sequence|yaml }}
{% endif -%}

View File

@ -0,0 +1,10 @@
{#
SPDX-FileCopyrightText: 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
base:
'*':
- match: list
- sys-pgp.install-client-qt

View File

@ -1,5 +1,5 @@
{#
SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-FileCopyrightText: 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}

View File

@ -1,5 +1,5 @@
{#
SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-FileCopyrightText: 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}

View File

@ -0,0 +1,30 @@
{#
SPDX-FileCopyrightText: 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
{% if grains['nodename'] != 'dom0' -%}
include:
- utils.tools.common.update
{% set pkg = {
'Debian': {
'pkg': ['pinentry-curses', 'pinentry-tty', 'pinentry-gnome3'],
},
'RedHat': {
'pkg': ['pinentry', 'pinentry-tty', 'pinentry-gnome3'],
},
}.get(grains.os_family) -%}
"{{ slsdotpath }}-installed-os-specific-pinentry":
pkg.installed:
- require:
- sls: utils.tools.common.update
- install_recommends: False
- skip_suggestions: True
- setopt: "install_weak_deps=False"
- pkgs: {{ pkg.pkg|sequence|yaml }}
{% endif -%}

View File

@ -0,0 +1,9 @@
{#
SPDX-FileCopyrightText: 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
base:
'tpl-sys-pgp':
- sys-pgp.install-pinentry