Title: Importer des clefs GnuPG dans sa Nitrokey Pro
Category: sécurité
Tags: GPG, open source, open hardware, Nitrokey, pl-fr
Date: 2019-07-28 23:10

Dans un [précédent article]({filename}../decouverte-de-la-nitrokey/index.md)
j'ai présenté la *Nitrockey Pro* et fait un bref tour du propriétaire. Cette
fois-ci je vais expliquer comment y importer des clefs PGP déjà existantes.

Bien entendu je pars sur un système déjà installé et configuré et part du
principe que la Nitrokey est paramétrée (PIN utilisateur et administrateur, nom
du propriétaire etc.)

## Avant de commencer

Voici la composition des clefs:

 - une *clé principale servant* a **créer des sous clefs, de les révoquer et 
     de signer celles des copains**.
 - une *sous clé* **permettant de chiffrer**
 - enfin une *sous clé* **permettant de signer**

A partir de là nous allons **mettre mes deux sous clefs sur la Nitrokey** et 
garder la clé principale dans un endroit sûr.

L'importation n'est pas très difficile et prendra qu'une minute. Par contre il
est important de réaliser quelques opérations en plus :

 - Créer un certificat de révocations.
 - Sauvegarder comme il se doit la clé maître et ses sous clefs, le certificat
     de révocation. En effet l'opération d'importation de vos sous clefs les
     supprimera du dossier `~/.GnuPG/`
 - Sortir ma *Master Key* du trousseau *GnuPG* pour la mettre en sécurité sur un
     périphérique de stockage externe (clé USB)

## Réaliser une sauvegarde

Avant tout, il est important de garder une copie de sauvegarde de sa clé maître
et de ses sous clefs au cas où une manipulation ne se passerait pas comme
prévu. Exportons les clefs privées, publiques et le certificat de révocation
dans un fichier compressé et chiffré.

Commençons par créer un dossier dans le répertoire `/tmp` afin de recevoir le
certificat de révocation et les sauvegardes de clefs : 

```shell
mkdir /tmp/gpg_backup
chmod 700 /tmp/gpg_backup
```

### Certificat de révocation

Voici la commande utile pour créer un certificat de révocation pour notre clé
maître :

```shell
gpg --gen-revoke --output /tmp/gpg_backup/revoke.cert <id>
```

Où `<id>` représente l'identifiant de la clé. Une boite de dialogue apparaît
ensuite demandant la phrase de passe permettant de débloquer la clé privée.

### Exporter les clefs

Commençons par la clé privée : 

```shell
gpg --export-secret-keys --armor --output /tmp/gpg_backup/ephase_private.asc <id>
```

Bien entendu la phrase de passe de la clé sera demandée

Puis la clé publique, qui ne nécessite pas de phrase de passe pour être
débloquée :

```shell
gpg --export --armor --output /tmp/gpg_backup/ephase_public.asc <id>
```

### Créer une archive sécurisée

Bien entendu il ne faut pas que ces données (du moins le certificat de
révocation et la clé privée) tombent entre de mauvaises mains, il suffit
simplement de créer une archive chiffrée du dossier `/tmp/gpg_backup` :

```shell
tar cz -C '/tmp/' gpg_backup | gpg --symmetric --output ephase_key.gpg && rm -rf /tmp/gpg_backup
```

Après avoir rentré un mot de passe de chiffrement fort pour protéger notre
sauvegarde, nous sommes fin prêt pour la suite des opérations. Pour restaurer le
dossier il suffira d'utiliser la commande suivante :

```shell
gpg --decrypt ephase_key.gpg | tar xz
```

### Mettre ce fichier à l'abri

Le fichier `ephase_key.gpg` sera mis à l'abri sur un espace de stockage hors
ligne (voir même plusieurs).

## Importer la paire de clefs

La manipulation se fait depuis la gestion de clefs `gpg`, nous y accédons avec
la commande : 

```shell
gpg --expert --edit-key <id>

gpg (GnuPG) 2.2.17; Copyright (C) 2019 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

La clef secrète est disponible.

sec  rsa4096/XXXXXXXXXXXXXXXX
     créé : 2016-07-07  expire : 2020-07-12  utilisation : SC
     confiance : ultime        validité : ultime
ssb  rsa4096/YYYYYYYYYYYYYYYY
     créé : 2016-07-07  expire : 2020-07-12  utilisation : E
ssb  rsa4096/ZZZZZZZZZZZZZZZZ
     créé : 2016-07-07  expire : 2020-07-12  utilisation : S
[  ultime ] (1). Yorick Barbanneau <ephase@example.com>

gpg>
```

À partir de là nous allons procéder par étape : 

 1. choisir la sous clé pour 1 (le chiffrement) et l'exporter dans le slot
    *chiffrement* sur la Nitrokey
 2. choisir la sous clé 2 (signature) et l'exporter dans le slot *signature*

La clé maitre sera sortie du trousseau et mise à l'abri.

### Exporter la clé ¨Chiffrement¨

Voici les commandes à entrer pour exporter la première clé sur la Nitrokey :

```shell
gpg> key 1

[...]

gpg> keytocard
```

`key 1` permet de dire à `gpg` que l'on travaille sur la première sous clé, et
`keytocard` envoi celle-ci sur notre *smartcard*

`gpg` nous demande de déverrouiller en entrant la phrase
de passe et le code *PIN* administrateur de la Nitrokey.


### Exporter la clé ¨Signature¨

Il faut maintenant dé-sélectionner la sous clé 1 :

```shell
gpg> key 1
```

Pour copier la clé 2:

```shell
gpg> key 2

[...]

gpg> keytocard
```

Comme précédemment, `gpg` nous demande de déverrouiller en entrant la phrase
de passe et le code *PIN* administrateur de la Nitrokey.

### Sauvegarder les changements.

Il ne reste plus qu'à sauvegarder nos changement sur les clefs et quitter `gpg`

```shell
gpg> save
```

Les deux sous clefs seront alors supprimées de notre trousseau et disponible
uniquement via la *smartcard*.

## Mettre sa clé maître à l'abri

La clé maître est la plus importante des clefs, elle permet de créer d'autre
sous clefs, d'émettre des certificats de révocation pour celles-ci ou encore de
signer les clefs publique des amis.

Il est tout à fait possible de la sortir du trousseau pour la mettre à l'abri
et de la remettre lorsque l'on en a besoin.

Pour ma part j'ai choisi de mettre la clé sur un support externe chiffré, et
avec l'aide d'un script de monter le support lorsque j'en ai besoin et de créer
un lien symbolique de la clé depuis le répertoire de `GnuPG`.

Les outils utilisés sont en général installés de base : `LUKS` et `udisk`

### Créer le conteneur chiffré

Toutes les opérations suivantes se font en **super utilisateur** ou avec `sudo`.

Dans un premier temps partitionnons la clé USB (ici `sdb`):

```shell
parted -s /dev/sdb mklabel msdos mkpart primary ext4 1MiB 100%
```

Il nous faut ensuite créer le conteneur chiffré :

```shell
cryptsetup luksFormat /dev/sdb1
WARNING!
========
Cette action écrasera définitivement les données sur /dev/sdb1.

Are you sure? (Type uppercase yes): YES
Saisissez la phrase secrète pour /dev/sdb1 :
Vérifiez la phrase secrète :
```

Le déverrouiller :

```shell
cryptsetup luksOpen /dev/sdb1 gpg_master
Saisissez la phrase secrète pour /dev/sdb1 :
```

Pour le formater :

```shell
mkfs.ext4 -E root_owner=1000:1000 -m 0 /dev/mapper/gpg_master
```
Il faut bien entendu adapter le paramètre `root_owner` en fonction de votre
`UID` et de votre `GID`.

Et enfin monter la partition avec :

```shell
mkdir -p /mnt/usb
mount /dev/mapper/gpg_master /mnt/usb
```

Puis s'assurer que la clé USB ne peut être lue seulement par notre utilisateur :

```shell
chmod 700 /mnt/usb
```

### Déplacer la clé maitre GnuPG sur votre clé USB

Les commandes suivantes sont à faire dans la foulée mais en tant **utilisateur
courant**.

Nous allons utiliser une fonctionnalité de `GnuPG 2` : les clefs privées sont
stockées dans le répertoire `~/.gnupg/private-keys-v1.d/` ou chaque fichier
correspond à une clé et le nom est repris dans le champs `keygrip` :

```shell
gpg -K --with-keygrip 
/home/ephase/.gnupg/pubring.kbx
-------------------------------
sec   rsa4096 2016-07-07 [SC] [expire : 2020-07-12]
      3526F4565D76C5674AA56690936CDF3783293949
      Keygrip = ABCDEF1234567890ABCDEF1234567890ABCDEF12
uid          [  ultime ] Yorick Barbanneau <ephase@example.com>
ssb>  rsa4096 2016-07-07 [E] [expire : 2020-07-12]
      Keygrip = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
ssb>  rsa4096 2016-07-07 [S] [expire : 2020-07-12]
      Keygrip = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
```

Je doit donc chercher la clé `3526F4565D76C5674AA56690936CDF3783293949.key` et
la copier sur notre clé :

```shell
mkdir -p /mnt/usb/.gpg_master
chown 700 /mnt/usb/.gpg_master
mv ~/.gnupg/private-keys-v1.d/3526F4565D76C5674AA56690936CDF3783293949.key /mnt/usb/.usbmaster
```

Afin de bien vérifier que la clé n'est plus disponible, il suffit de faire :

```shell
gpg -K
/home/ephase/.gnupg/pubring.kbx
-------------------------------
sec#  rsa4096 2016-07-07 [SC] [expire : 2020-07-12]
      3526F4565D76C5674AA56690936CDF3783293949
uid          [  ultime ] Yorick Barbanneau <ephase@example.com>
ssb>  rsa4096 2016-07-07 [E] [expire : 2020-07-12]
ssb>  rsa4096 2016-07-07 [S] [expire : 2020-07-12]
```

Le `#` à côté de `sec` indique que la clé maître n'est plus disponible dans le
trousseau `GnuPG`.

### Automatiser le montage de la clé

Afin de faciliter les opérations de montage et démontage de la clé USB
contenant notre clé maître, on va s'aider d'un script. 

L'utilisation est simple, une fois mis dans un endroit accessible via le `$PATH`
il suffit de faire `gpgmount.sh m` pour monter la clé USB ou `gpgmount.sh u` 
pour la démonter.

```bash
#!/bin/bash

UUID=""
mountpoint=""

usage () {
cat <<EOF 
$0 m | u
$0 mount | unmount
    
mount or unmount encrypted device based on UUID and attach private keys
EOF
}

if [ -L "/dev/disk/by-uuid/${UUID}" ]
then
    case "$@" in
        "m"|"mount")

            echo "Mount encryted key"
            action=$(udisksctl unlock -b /dev/disk/by-uuid/${UUID})

            if [ ! $? -eq 0 ]
            then
                echo $action
                exit 10
            fi
            mountpoint=$(udisksctl mount -b /dev/mapper/luks-${UUID} | \
                awk '{print $4}')
            
            while read -r f
            do
                base=$(basename $f)

                #create symlink to key file if not exist
                if [ ! -e "~/.gnupg/private-keys-v1.d/$base" ]
                then
                    ln -s $f ~/.gnupg/private-keys-v1.d/$base
                fi
            done < <(find ${mountpoint%.}/.gpg_master/ -type f -name "*.key")
        ;;
        "u"|"unmount")
            echo "unmount encrypted key"
            while read -r f
            do
                rm $f
            done < <(find ~/.gnupg/private-keys-v1.d -type l -name "*.key")

            udisksctl unmount -b /dev/mapper/luks-${UUID} 2&> /dev/null || \
                echo "Volume is already unmounted"
            udisksctl lock -b /dev/disk/by-uuid/${UUID} 2&> /dev/null || \
                echo "Encrypted container is not unlocked"
        ;;
        *)
            echo "parameter not understood, what do you want :"
            usage
            exit 1
        ;;
    esac
else
    echo "USB device $UUID is not connected"
    exit 5
fi

exit 0
```

Il faut bien entendu mettre l'uuid de la partition contenant notre clé maître
dans la variable `UUID`.

Pour le récupérer il suffit de lancer la commande `blkid` en tant que `root` 
avec en paramètre la partition en question:

```shell
blkid /dev/sdb1
/dev/sdb1: UUID="<uuid>" TYPE="crypto_LUKS" PARTUUID="<partuuid>"
```

## En conlusion

J'ai essayé ici de créer un environnement équilibré entre sécurité et facilité.
La Nitrokey permet donc de sécuriser mes sous clefs utilisées tous les jours
tout en les rendant disponibles sur mes deux machines principales.

Bien sûr il serait plus sécurisé de n'utiliser la clé maître sur une machine
totalement hors ligne démarrée par une distribution live. Mais avouez que pour
signer les clé des amis (lors de [chiffro-fête][l_w_cparty] par exemple), ce 
n'est pas l'idéal.

[l_w_cparty]:https://fr.wikipedia.org/wiki/CryptoParty

## Bibliographie

*Kernel Maintainer PGP guide — The Linux Kernel documentation* par Konstantin 
Ryabitsev - [lien][b_pgpkernmaint]

*Using an offline GnuPG master key* (2015) par  Damien Goutte-Gattat - 
[lien][b_offlinegpgk]

[b_pgpkernmaint]:https://www.kernel.org/doc/html/v5.1/process/maintainer-pgp-guide.html
[b_offlinegpgk]:https://incenp.org/notes/2015/using-an-offline-gnupg-master-key.html
