nimag42 J'écris des trucs ici.
15 déc. 2020

Du fonctionnement des sous-clés avec GPG

Je me suis récemment pris la tête à essayer de comprendre à quoi servent les sous-clés dans GPG et comment elles fonctionnent. J'avais besoin de générer une nouvelle paire de clés car j'ai un nouveau téléphone sur lequel je souhaitais installer un nouvelle paire de clés pour gérer mes mails signés/chiffrés et déchiffrer mon dictionnaire de mot de passe (j'utilise pass, un outil linux standard qui se contente de chiffrer vos mots de passes dans une arboresence de fichier avec PGP).

Note pratique, si par malheur vous faites un control-c dans le pinentry curses (l'espèce de prompt en ligne de commande qui vous demande de tapez votre mot de passe) vous risquez de le casser définitivement. Pour le refaire marcher il faut le tuer proprement avec la commande gpgconf --kill gpg-agent

Détails des clés avec GPG

Pour commencer mon explication, créons une nouvelle identitée pour monsieur Prout, par défaut, sur gpg : gpg --gen-key

On remplis le nom, le mail, on entre une phrase secrète (attention gpg ne vous prévient pas que votre mot de passe n'est pas assez complexe et plante silencieusement). Et la si on liste les clés disponibles :

$ gpg -K
sec   rsa3072 2020-12-15 [SC] [expire : 2022-12-15]
      6EEFD1BAF2205BB81B746999022229C692ABDD61
uid          [  ultime ] Prout prout <prout@prout.prout>
ssb   rsa3072 2020-12-15 [E] [expire : 2022-12-15]

On voit deux lignes avec des informations de clés (algorithme, taille, date d'expiration):

sec   rsa3072 2020-12-15 [SC] [expire : 2022-12-15]
ssb   rsa3072 2020-12-15 [E] [expire : 2022-12-15]

La première est, selon le vocabulaire de gpg, la clé maître. La seconde est une "sous clé de chiffrement". En realité, les deux lignes correspondent chacune a une paire de clé publique/privée qui sont indépendantes l'une d'entre elles. Notez bien, à chaque fois qu'on parle de clé, c'est en réalité un abus de langage pour parler d'un couple de clé privée/publique. Sous le capot, GPG à simplement des métadonnées qui associent aux clés ces "statuts" particulier.

D'autre part, on voit aussi une information entre crochet : SC ou E. Ces lettres correspondent aux 3 rôles qu'une clé peut avoir :

  • S: signature, la clé privée du couple sert à signer un message et toutes les personnes ayant la clé publique peuvent le déchiffrer, et s'assurer que le message provient bien le personne qui possède la clé.
  • C: certify, la clé privée sert à signer des clés publiques, pour établir des relations de confiance. C'est avec cette clé là que vous pouver certifier les clés d'autres personnes, ou vos propre sous clés, pour apporter votre preuve de confiance à des identités.
  • E: encrypt, la clé publique sert à chiffre un message que seule la personne possédant la clé privée (nous) pourra déchiffrer.

Il existe un dernier rôle, plus récent, noté 'A', servant a décrire le rôle d'authentification d'une clé, dans le cas par exemple de l'utilisation de clé gpg pour l'authentification dans le protocole SSH.

En réalité, tout couple de clé privée / clé publique peut réaliser ses 4 rôles. Il s'agit simplement d'une séparation arbitraire des pouvoirs que GPG (soit par défaut, soit par vos choix) applique.

Par défaut donc, gpg vous crée une clé SC, qui à le double pouvoir de signer des messages et de certifier des identités; puis une clé E qui est celle qui va être utilisée pour déchiffrer des messages qu'on vous envoie. A noter qu'il est tout à fait possible de faire en sorte que sa clé maître n'ai pas le rôle S, uniquement le C, et avoir une autre sous-clé qui ai le rôle S.

Une question naturelle qui se pose est alors, pourquoi se compliquer la vie et ne pas avoir une seule paire de clé qui a les 3 rôles, au lieu de ségreger le rôle de chiffrement à une autre clé ? Une partie de l'explication vient du fait que certains algorithmes de chiffrement (RSA par exemple) ont besoin d'avoir des clés différentes pour fonctionner de façon sécuritaire.

Par exemple, il y a un faille assez basique si vous utilisez la même clé privée de votre paire de clé pour signer et déchiffrer vos messages, imaginons qu'Eve récupère un message chiffré à votre destination, si elle parvient par social ingeneering à vous demander de signer ce dit message, en réalité vous le déchifrerez et lui enverrez puisque d'un point de vue mathémique il s'agit de la même chose.

Donc, gpg pour contrer va par défaut nous créer deux paire de clés, l'une est utilisée pour signer et certifier, l'autre pour déchiffrer.

Lorsque l'on envoie nos clés sur les serveurs de partage de clés publiques, avec gpg --send-keys, gpg va envoyer les clés publiques de tout nos couples de clés présents, donc la SC et la E, mais aussi toutes celles d'autres sous-clés que l'on aurait pu créer.

Que se passe-t-il si l'on s'amuse à créer d'autre sous clés ?

Signature

On pourrait éventuellement s'amuser à vouloir créer d'autre sous clés.

On lance donc gpg --edit-key Prout (remarquez comment gpg est sympa, on peut juste lui passer un morceau du nom et il comprend de quel identité/jeux de clé on parle, sinon passez lui l'id de la clé maître, ou son empreinte) puis on lance la commande addkey. On a alors le choix de l'algorithme et du rôle (chiffrement ou signature, on ne nous propose de créer d'autre clé de certification). Un petit save et voila, on s'est créé une nouvelle sous clés (en réalité un nouvelle paire de clé privée/publique) avec le pouvoir pour signer des messages.

gpg> list

sec  rsa3072/022229C692ABDD61
     créé : 2020-12-15  expire : 2022-12-15  utilisation : SC  
     confiance : ultime        validité : ultime
ssb  rsa3072/A3AFEC937A66A529
     créé : 2020-12-15  expire : 2022-12-15  utilisation : E   
ssb  rsa3072/BB5273F3CDCF5B13
     créé : 2020-12-15  expire : jamais      utilisation : S   
[  ultime ] (1). Prout prout <prout@prout.prout>

Si maintenant on signe un message avec notre compte :

$ echo "coucou c'est moi \!" > msg
$ gpg --sign --clear-sign -u Prout msg
$ cat msg.asc
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

coucou c'est moi !
-----BEGIN PGP SIGNATURE-----

iQHABAEBCgAqFiEE7/gaAz0BuY++VHL0u1Jz883PWxMFAl/YuBsMHHByb3V0QG9w
cm91AAoJELtSc/PNz1sTrPEMAJoq5Z2KW/NgPfFBovOKGpcLegZOMXKX9VfKnHFL
6eVdCesVGKFl49rNlazc8tVhCa5kRILbReWA5YN6DpduMkHVeW67CTjJGA5at+KB
JSx42dD6IRe6ba9yB2a1t3BoX8I2sikvX3CPI9Mlqlve1rd82m88UfNkTUxZDNA3
qDOKOz8FYPLJXki2m2f+lgPavyUGSIRYLEmxOlVTiW4pKVXGJ90yPEzQUweaA39b
ySZC1mShK/XDgC0Gq52sEkrkK5vmP4oHr5uTLRQt9RgrsHPNxXCz47sCWp6ZcxqU
t0d9py5EvSG4yyu9pPr015nvxOYKApM+40zEwaAs4Ip4Vuc/wtlPGb6Ga8J6IjaH
Gj7IkLMQcsVfnCQErnKmtbGR5EkYtjlH0WCSOp+oIkI4cYcBqiaFbjTCORWw+E+Y
AF1XeXk8lxFz5tuCUmsg9bOcAVSMXDZvG5BBRNww04o3Z7Gofsm1S2fuZLYLSfRs
xsx4IdC5RsZCjsG2xhY/+lu3GA==
=7HpN
-----END PGP SIGNATURE-----

Et si on essaie de vérifier la signature, comme GPG a la clé privée :

$ gpg --verify msg.asc
gpg: Signature faite le mar. 15 déc. 2020 14:20:27 CET
gpg: avec la clef RSA EFF81A033D01B98FBE5472F4BB5273F3CDCF5B13
gpg: issuer "prout@prout.prout"
gpg: Bonne signature de « Prout prout <prout@prout.prout> » [ultime]

Et vous constatez que l'empreinte de la clé (EFF81A033D01B98FBE5472F4 BB5273F3CDCF5B13 ) de la signature correspond a l'id de la sous-clé de signature qu'on a crée, l'id correspond aux 8 derniers octets de l'empreinte (ssb rsa3072/ BB5273F3CDCF5B13).

(Si après vous décidez de bidouiller le fichier en modifiant la signature, et que vous retentez, plus aucune correspondance trouvée, ce qui est le comportement voulu !)

Par défaut on se rend compte que gpg va toujours utiliser votre plus récente clé de signature valide pour signer vos messages, et que c'est donc la clé privée de cette sous-clé qui doit être utilisée par un tiers pour vérifier la signature de l'un de vos message. GPG fait ceci automatiquement bien entendu si vous possédez une version à jour de l'identité numérique d'une personne (via les serveurs de clés).

Chiffrement/Déchiffrement

Maintenant je vais créer une nouvelle clé de chiffrement et voir ce qu'il se passe.

$ gpg --edit-key 6EEFD1BAF2205BB81B746999022229C692ABDD61
gpg> addkey
# On rentre les infos de la nouvelle clée
gpg> list

sec  rsa3072/022229C692ABDD61
     créé : 2020-12-15  expire : 2022-12-15  utilisation : SC  
     confiance : ultime        validité : ultime
ssb  rsa3072/A3AFEC937A66A529
     créé : 2020-12-15  expire : 2022-12-15  utilisation : E   
ssb  rsa3072/BB5273F3CDCF5B13
     créé : 2020-12-15  expire : jamais      utilisation : S   
ssb  rsa3072/C5E21A31259E52EF
     créé : 2020-12-15  expire : jamais      utilisation : E   
[  ultime ] (1). Prout prout <prout@prout.prout>
gpg> save

Je peux utiliser mon autre identité pour envoyer un message chiffré à ma nouvelle identité Prout, puis que je tente de déchiffrer ce message :

$ gpg --encrypt -r Prout -u Théo msg
$ gpg --decrpyt msg.gpg

Veuillez entrer la phrase secrète pour déverrouiller la clef secrète
 OpenPGP :                                                          
 « Prout prout <prout@prout.prout> »                                          
 clef RSA de 3072 bits, identifiant C5E21A31259E52EF,                   
 créée le 2020-12-15 (identifiant de clef principale 022229C692ABDD61.

On voit donc que, similairement au sous-clé de signature, le message a été chiffré en utilisant la sous-clé de chiffrement la plus récente et que c'est la clé publique de cette sous-clé qui doit être utilisé pour envoyer un message chiffré à Prout.

Pourquoi vouloir utiliser des sous clés différentes ?

On a vu qu'il est utile de séparer sa clé de signature de sa clé de chiffrement.

Mais pourquoi avec besoin de plus de sous-clés ?

En réalité ces nouvelles sous-clés sont utiles pour gérer la sécurité de votre identité. Votre clé principale, avec le pouvoir de certification (C), vous sert à vérifer d'autre identité et à être vérifier par d'autres identités. C'est grace a ce mécanisme qu'on peut établir une toile de confiance et faire confiance au fait que vous êtes cette identité numérique. Si jamais par malheur on se fait pirater cette identité, que quelqu'un accède à la clé privée de la clé maître, et sa phrase de passe, on est fichu. Il n'y a plus aucun moyen d'assurer qu'on contrôle cette identité numérique.

On va pouvoir alors utiliser les sous-clés comme des boucliers numériques d'identité temporaire qu'on utilise dans la vie de tout les jours. On peut imaginer conserver sa clé maître cachée dans un media sécurisé et hors-ligne, par exemple dans un disque dur dans un coffre-fort, et n'utiliser que les sous clés E S générées pour signer et déchiffrer des messages de tout les jours. Debian vous conseille d'ailleur d'aller plus loin en stockant votre clé maître dans un dongeon caché derrière un labyrinthe gardé des samuraïs, à vous de voir.

De cette façon, si un jour les clés que l'on utilise se font pirater, on peut alors aller chercher notre clé maître sur ce disque dur, et avec cette clé maître qui est celle qui a la confiance des autres, déclarer la révocation des sous clés, dès lors vous gardez la confiance que vous avez avec vos pairs sur votre clé maîtres, mais vous leurs dites de ne plus faire confiance aux anciennes clés, puis vous pouvez générer de nouvelles sous clés et dires autres de faire confiance à celles-ci.

Dans l'idée, on veut donc enlever la clé maître et conserver uniquement une sous-clé de signature et une sous-clé de chiffrement. Bien évidemment, gpg ne permet pas de le faire simplement (ça aurait été trop facile), il faut donc exporter la clé maître, la stocker dans un endroit sécuriser, exporter les sous-clé qu'on veut utiliser, supprimer la clé privée maître (ce qui supprimera toutes les clés privées), puis réimporter les sous-clés :

$ gpg --edit-key Prout
gpg> list
sec  rsa3072/022229C692ABDD61d
     créé : 2020-12-15  expire : 2022-12-15  utilisation : SC  
     confiance : ultime        validité : ultime
ssb  rsa3072/A3AFEC937A66A529
     créé : 2020-12-15  expire : 2022-12-15  utilisation : E   
ssb  rsa3072/BB5273F3CDCF5B13
     créé : 2020-12-15  expire : jamais      utilisation : S   
ssb  rsa3072/C5E21A31259E52EF
     créé : 2020-12-15  expire : jamais      utilisation : E   
[  ultime ] (1). Prout prout <prout@prout.prout>
> quit
$ gpg --output prout.private.asc --armor --export-secret-keys Prout
$ gpg --output prout.subkeys.private.asc --armor --export-secret-subkeys Prout
$ gpg --delete-secret-keys Prout

L'option --armor indique a gpg d'écrire les clés en caractère ascii et non en binaire, c'est lisible et plus pratique pour les canaux qui gèrent mal autre chose que l'ascii. Après avoir confirmer plein de fois, nous y voila, gpg -K nous montre qu'on a plus aucune clé privée tandis que gpg -k nous montre qu'on a encore les clés publiques (oui c'est la différence entre -k et -K).

Maintenant, si on essaie de réimporter les sous clés :

$ gpg --import prout.subkeys.private.asc
$ gpg -K
sec#  rsa3072 2020-12-15 [SC] [expire : 2022-12-15]
      6EEFD1BAF2205BB81B746999022229C692ABDD61
uid          [  ultime ] Prout prout <prout@oprou>
ssb   rsa3072 2020-12-15 [E] [expire : 2022-12-15]
ssb   rsa3072 2020-12-15 [S]
ssb   rsa3072 2020-12-15 [E]

La présence du # après sec est l'indication que la clé privée n'est pas disponible, gpg ne la connait plus. On dit que c'est une clé dépouillée. Si vous essayez de faire des certifications maintenant avec ce compte, ou d'ajouter de nouvelles sous-clés, ça ne marchera plus:

$ gpg --edit-key Prout
gpg> addkey
La clef secrète est nécessaire pour faire cela.
gpg>

Maintenant par contre, pour peu que vous ayez correctement copié et supprimé le fichier prout.private.asc, votre clé maître est maintenant en toute sécurité protégée par vos assassins ninjas dans votre bunker.

Les oeufs dans le même panier

On peut aller un tout petit plus loin, si vous avez plusieurs devices (un ordi, un téléphone), et que chacun de vos devices à des chances de se faire pirater, vous pouvez limiter les dégâts en ayant une sous-clé de signature différente pour chaque device.

De cette façon, si un device se fait pirater, vous révoquer la sous-clé de signature de ce device, mais pas les sous clés de signature des autres devices.

Il n'est par contre pas vraiment conseillé d'avoir une clé de chiffrement différentes pour chaque device puisque, comme vous l'avez vu avant, par défaut un tiers va chiffrer un message à votre destination en utilisant la clé publique de votre plus récente sous-clé de chiffrement, et donc seul votre device le plus récent pourra déchiffrer les messages qui vous sont adresser. Vous pourriez éventuellement contrebalancer ça en demandant à vos pairs de signer leurs messages en multi-signature avec toutes vos clés publiques de toutes vos sous-clés de chiffrement, mais a mon avis vous allez passer pour un relou.

Maintenant, si jamais vous voulez exportez une sous-clé spécifique, pour refaire la manip de tout à l'heure mais ne pas garder toutes les sous clés sur votre ordi, si vous utilisez le nom ou l'id d'une clé, gpg va exporter de force celle par défaut (la clé la plus récente valide). Si vous voulez forcer, vous devez mettre l'id de la sous clé (les 8 dernières hex de l'empreinte), suivi d'un point d'exclamation : gpg --export-secret-subkeys A3AFEC937A66A529!.

Gestion de plusieurs sous-clés de chiffrement avec pass

Pass est un outil KISS de gestion des mots de passes, les mots de passes sont simplement stockées sous l'arborescence que vous voulez, et chiffré avec votre clé gpg.

Si vous avez suivi, par défaut ils sont chiffrés donc avec la plus récente sous-clé E que vous possédez.

$ pass init 6EEFD1BAF2205BB81B746999022229C692ABDD61
$ pass insert --generate test
$ gpg .password-store/test.gpg
gpg: chiffré avec une clef RSA de 4096 bits, identifiant A3AFEC937A66A529, créée le 2020-12-15

Si vous avez plusieurs sous-clé de chiffrement, vous pouvez forcer pass à chiffre tous vos mots de passes avec toutes les clés publiques des sous-clés de chiffrement que vous avez, en utilisant l'astuce du point d'exclamation :

$ pass init A3AFEC937A66A529! C5E21A31259E52EF!
$ pass insert --generate test
$ gpg .password-store/test.gpg
gpg: chiffré avec une clef RSA de 4096 bits, identifiant A3AFEC937A66A529, créée le 2020-12-15

Sources

Mes billets archivés