Sicheres GnuPG Setup: Primary Key offline speichern

Hier wird ein Setup von GnuPG beschrieben, welches den privaten Teil vom Primary Key auf einem verschlüsselten USB Stick offline speichert. Dies hat folgende Vorteile: Wird in das System eingebrochen, hat der Angreifer nur Zugriff auf die Subkeys und nicht auf den Primary Key. Dann muss man nicht alle Keys widerrufen, sondern nur die Subkeys. Dies hat bedeutet, dass die vorhandenen Key Signaturen behalten werden können und man nach belieben neue Keys zum Verschlüsseln und Signieren generieren kann ohne den Personen den neuen Key mitzuteilen, da der Primary Key unverändert bleibt.

GPG Key generieren

Diese Anleitung basiert auf der GnuPG Version 2.1.1.

Zuerst wird ein neuer GPG Key generiert. Dies wird mit der Option --full-gen-key gemacht, da man nur damit eine eigene Schlüsselgrösse angeben kann.

$ gpg --full-gen-key

Folgende Angaben werden benötigt:

  • (1) RSA and RSA (default): Algorithmus zum Verschlüsseln und Signieren
  • 4096: Schlüsselgrösse wird 4096 Bit
  • 2y: Der Schlüssel läuft in zwei Jahren automatisch ab
    • (Hinweis: Das Ablaufdatum kann aber jederzeit geändert werden.
      Falls man den Schlüssel aber verlieren sollte, ist man froh,
      wenn dieser automatisch nach einer gewissen Zeit ungültig wird)
  • Rainer Zufall: Vorname und Name
  • rainer.zufall@example.net: E-Mail Adresse

Dann wird man aufgefordert eine Passphrase einzugeben. Mit dieser wird der Key geschützt und sollte deshalb nicht zu einfach sein. Dauert das Generieren des Keys zu lange, liegt das daran, dass das Device /dev/random nur sehr wenig Zufallswerte liefert. Durch Tastatureingaben und Mausbewegungen wird mehr Entropie erzeugt. Hilfreich ist das Installieren und Aktivieren von haveged, ein Daemon welcher mehr Zufallszahlen generiert. Haveged gilt als sicher.

In diesem Beispiel hat der Key die Key ID 0xB1940999 erhalten.

Zusätzliche User IDs hinzufügen

Möchte man den Key für verschiedene E-Mail Adressen verwenden, kann man zusätzliche User IDs hinzufügen:

$ gpg --edit-key 0xB1940999
gpg> adduid
Real name: Rainer Zufall
Email address: rainer.zufall@example.org
gpg> save

Keys und ihre Eigenschaften anzeigen

Mit -K werden die Private Keys aufgelistet. Mit -k werden die Public Keys aufgelistet. Für welche Zwecke die Schlüssel benutzt werden können, ist mit der Option --list-options show-usage zu sehen.

$ gpg --list-options show-usage -K 0xB1940999
sec   rsa4096/B1940999 2014-12-29 [SC] [expires: 2016-12-28]
uid       [ultimate] Rainer Zufall <rainer.zufall@example.org>
uid       [ultimate] Rainer Zufall <rainer.zufall@example.net>
ssb   rsa4096/3EF3EA29 2014-12-29 [E] [expires: 2016-12-28]

Die erste Zeile gibt an, dass dies ein Private Key ist (sec). Danach sieht man die zwei erstellten User IDs. In der letzten Zeile sieht man, dass wir ein Subkey haben.

Was man mit den Keys machen kann, ist in den eckigen Klammern beschrieben. Dieses Verhalten finde ich nützlich und kann mittels list-options show-usage in der Konfigurationsdatei ~/.gnupg/gpg.conf standardmässig aktiviert werden. Zusätzlich ergänzte ich die Konfigurationsdatei mit keyid-format 0xshort, damit die Key IDs mit führendem 0x angezeigt werden. Aus der Manpage von gpg liest man zu den Verwendungszwecken folgendes:

  • E = encryption: Nachrichten ver/entschlüsseln
  • S = signing: Nachrichten signieren / Signatur von Nachrichten überprüfen
  • C = certification: Keys signieren / Signatur von Keys überprüfen
  • A = authentication: Sich gegenüber einem Dienst ausweisen

Der Primary Key 0xB1940999 wird also zum Signieren und zum Zertifizieren benötigt. Der Subkey wird zum entschlüsseln benötigt.

Unser Ziel ist es ein separater Key zum Signieren und Zertifizieren zu erstellen.

Separater Key zum signieren erstellen

Jetzt erstellen wir ein neuen Subkey, mit welchem nur signiert wird:

$ gpg --edit-key 0xB1940999
gpg> addkey
(4) RSA (sign only)
[...]
gpg> save

Der Vorgang ist gleich wie beim erzeugen eines komplett neuen Keys, ausser das als Typ (4) RSA (sign only) ausgewählt wird.

Werden jetzt die Private Keys aufgelistet, sieht man, dass ein neuer Key vorhanden ist, mit welchem man Nachrichten signieren ([S]) kann (letzte Zeile):

$ gpg -K
/home/emanuel/.gnupg/pubring.kbx
--------------------------------
sec   rsa4096/0xB1940999 2014-12-29 [SC] [expires: 2016-12-28]
uid         [ultimate] Rainer Zufall <rainer.zufall@example.org>
uid         [ultimate] Rainer Zufall <rainer.zufall@example.net>
ssb   rsa4096/0x3EF3EA29 2014-12-29 [E] [expires: 2016-12-28]
ssb   rsa4096/0xD142AA3C 2014-12-29 [S] [expires: 2016-12-28]

Zusammengefasst sieht unser Setup jetzt so aus:

  • Der Primary Key 0xB1940999 kann signieren und zertifizieren
  • Der Subkey 0x3EF3EA29 kann entschlüsseln
  • Der Subkey 0xD142AA3C kann signieren

Wir möchten privaten Teil vom Schlüssel 0xB1940999 auf ein verschlüsselten USB Stick auslagern.

Keys publizieren

Zuerst konfiguriert man GnuPG, dass ein Keyserver aus einem Pool ausgewählt wird. So hat man keine Probleme, falls der fix eingestellte Keyserver nicht erreichbar sein sollte. Dies wird in der Konfigurationsdatei ~/.gnupg/gpg.conf mit keyserver angegeben. Mit no-honor-keyserver-url sagt man, dass immer der lokal eingetragene Keyserver aus dem Pool verwendet werden soll.

keyserver hkps://hkps.pool.sks-keyservers.net
keyserver-options no-honor-keyserver-url

Der Key kann folgendermassen auf ein Keyserver geladen werden:

$ gpg --send-keys 0xB1940999

So kann auf Keyservern nach Public Keys gesucht werden:

$ gpg --search-key Rainer Zufall

Möchte man den Public Key exportieren um beispielsweise auf einer Webseite zu veröffentlichen, kann das so gemacht werden:

$ gpg --armor --export-options export-minimal --export 0xB1940999

Backup der Keys erstellen

Um ein Backup der Keys zu erstellen, kann man das ganze ~/.gnupg Verzeichnis auf ein externes Medium speichern und sicher aufbewahren. Dieses Medium kann zusätzlich verschlüsselt werden (vgl. nächstes Kapitel).

$ cp -r .gnupg/ /mnt/securedevice

Ein Wiederrufszertifikat kann folgendermassen erstellt werden:

$ gpg --gen-revoke --armor 0xB1940999 > 0xB1940999_revoke.asc

Der Private Key inklusive die privaten Subkeys können folgendermassen exportiert und allenfalls auch ausgedruckt sicher aufbewahrt werden:

$ gpg --armor --export-secret-keys 0xB1940999 > 0xB1940999_private_keys.asc

Verschlüsselten USB Stick erstellen

Hierzu löscht man alle vorhandenen Partitionen und fügt eine neue hinzu. Dies kann man beispielsweise mit cfdisk machen. In meinem Beispiel wurde dem USB Stick das Device /dev/sdc zugewiesen.

$ sudo cfdisk /dev/sdc

Jetzt verschlüsselt man mit cryptsetup das Device:

$ sudo cryptsetup -c aes-xts-plain -y -s 512 luksFormat /dev/sdc1

WARNING!
========
This will overwrite data on /dev/sdc1 irrevocably.

Are you sure? (Type uppercase yes): YES
Enter passphrase:
Verify passphrase:

Das Blöckgerät kann folgendermassen entschlüsselt werden:

$ sudo cryptsetup luksOpen /dev/sdc1 securegpg
Enter passphrase for /dev/sdc1:

Nach dem Eingeben der Passphrase gibt es ein neues Gerät in /dev/mapper/securepgp. Auf dem wird ein neues Dateisystem angelegt:

$ mkfs.ext4 /dev/mapper/securegpg

Dieses Dateisystem kann gemountet werden:

$ mount /dev/mapper/securegpg  /media/securegpg

Folgendermassen entfernt man den USB Stick wieder vom System:

$ umount /media/securegpg
$ cryptsetup luksClose /dev/mapper/securegpg

Der USB Stick ist jetzt einsatzbereit.

Privaten Primary Key auf USB Stick auslagern

Zuerst mounten wir den USB Stick und kopieren das Verzeichnis ~/.gnupg darauf:

$ sudo cryptsetup luksOpen /dev/sdc1 securegpg
Enter passphrase for /dev/sdc1:
$ mount /dev/mapper/securgpg  /media/securegpg
$ cp -r .gnupg /media/securegpg/

Dann löschen wir alle Private Keys (es gibt keine Option zum nur den Primary Key ohne die Subkeys zu löschen):

$ gpg --delete-secret-keys 0xB1940999

Da dies eine eher heikle Operation ist, müssen wir diese für jeden Privat Key bestätigen.

Jetzt besitzen wir aber gar kein Private Key mehr im Verzeichnis ~/.gnupg. Der Primary Key wollen wir dort nicht haben, aber die zwei Subkeys zum Entschlüsseln und Zertifizieren. In GnuPG kann mit der Option --homedir das GnuPG Verzeichnis mit dem Schlüsselmaterial angegeben werden. So können wir die Subkeys vom USB Stick exportieren und in die lokale Installation importieren:

$ gpg --homedir /mnt/securegpg/.gnupg/ --export-secret-subkeys | gpg --import

Dazu müssen wir die Passphrases der Private Keys eingeben.

Werden jetzt die Private Keys aufgelistet, sieht man am Hash (#), dass der private Teil des Primary Keys fehlt, aber der Subkeys vorhanden sind.

$ gpg -K
/home/emanuel/.gnupg/pubring.kbx
--------------------------------
sec#  rsa4096/0xB1940999 2014-12-29 [SC] [expires: 2016-12-28]
uid         [ultimate] Rainer Zufall <rainer.zufall@example.org>
uid         [ultimate] Rainer Zufall <rainer.zufall@example.net>
ssb   rsa4096/0x3EF3EA29 2014-12-29 [E] [expires: 2016-12-28]
ssb   rsa4096/0xD142AA3C 2014-12-29 [S] [expires: 2016-12-28]

Somit ist unser Ziel erreicht: Der Private Teil des Primary Keys ist nur noch auf dem USB Stick gespeichert. Wenn wir jetzt Nachrichten signieren, wird der Subkey 0xD142AA3C verwendet und nicht der Primary Key.

Eigenen Key signieren lassen

Man kann sich wie gewohnt der Primary Key signieren lassen. An diesem Vorgang ändert sich nichts.

Fremde Keys signieren

Der Vorgang um fremde Keys zu signieren ist folgnder:

  • Fremder Public Key importieren
  • Fingerprint überprüfen
  • Falls OK, weiterfahren. Sonst abbrechen.
  • USB Stick entschlüsseln und mounten.
  • Public Key exportieren auf USB Stick importieren
  • Public Key auf USB Stick signieren
  • Public Key wieder auf die Keyserver hochladen
  • Signierter Key vom USB Stick exportieren und lokal importieren

Angenommen ich möchte den Key 0x23F00BA2 signieren. Dabei geht man folgendermassen vor:

Key von Keyserver importieren:

$ gpg --recv-key 0x23F00BA2

Der Key kann auch von einer Datei importiert werden:

$ gpg --import < key.asc

Fingerprint anzeigen und mit Fingerprint vergleichen, welcher man von der Person erhalten hat.

$ gpg --fingerprint 0x23F00BA2

Falls der Fingerprint ok ist, fährt man weiter. Sonst bricht man ab.

Jetzt wird der USB Stick eingesteckt und gemountet:

$ sudo cryptsetup luksOpen /dev/sdc1 securegpg
Enter passphrase for /dev/sdc1:
$ mount /dev/mapper/securegpg  /media/securegpg

Dann wird der Key exportiert und auf dem USB Stick importiert:

$ gpg --export 0x23F00BA2 | gpg --homedir /media/securegpg --import

Und anschliessend auf der GnuPG Installation vom USB Stick signiert:

$ gpg --homedir /media/securegpg --sign-key 0x23F00BA2

Der signierte Key kann wieder auf die Keyserver geladen werden:

$ gpg --homedir /media/securegpg --send-keys 0x23F00BA2

Damit der signierte Key auch lokal vorhanden ist, kann man den vom USB Stick
exportieren und lokal wieder importieren:

$ gpg --homedir /media/securegpg --export 0x23F00BA2 | gpg --import

Am Schluss wird der USB Stick wieder entfernt:

$ umount /media/securegpg
$ cryptsetup luksClose /dev/mapper/securegpg

Falls der gpg-agent noch auf dem Dateisystem sitzt, kann man diesen mit pkill gpg-agent stoppen. Bei der nächsten Verwendung von GnuPG wird dieser wieder gestartet.

Jetzt ist der Vorgang abgeschlossen: Der Key 0x23F00BA2 wurde mit dem Private Key welcher sich auf dem USB Stick befindet signiert, auf die Keyserver geladen und in der lokalen GnuPG Installation importiert.

Fremde Keys mit einem Skript signieren

Der obige Vorgang sieht etwas kompliziert aus und ist wenn man oft Keys signiert nicht sehr praktisch. Folgendes Skript nimmt einem die Tipparbeit ab:

#!/bin/bash

KEY="$1"
SECUREDEVICE="/dev/${2:-sdc1}"
SECUREDEVICENAME="securegpg"
SECUREHOME="/media/securegpg"
SECUREGPGDIR="$SECUREHOME/.gnupg"

PrintUsage(){
  cat <<< EOI
Usage:
  securegpgsign key [devicename]
  securegpgsign -h | --help

Default Device name is sdc1

Examples:
  securegpgsign 0x23FOOBA2
  securegpgsign 0x23FOOBA2 sde

EOI

}

if  [[ $TEST == "-h" || $TEST == "--help" ]]
then
  PrintUsage
fi

if (($# < 1))
then
  PrintUsage
  exit 1
fi

gpg --recv-key "$KEY"
gpg --fingerprint "$KEY"

echo "Is the fingerprint correct?"
echo "Press Enter to continue or ^C to canel."
read

cryptsetup luksOpen "$SECUREDEVICE" "$SECUREDEVICENAME"
mount "/dev/mapper/$SECUREDEVICENAME" "$SECUREHOME"

gpg --export "$KEY"  | gpg --homedir "$SECUREGPGDIR" --import
gpg --homedir "$SECUREGPGDIR" --sign-key "$KEY"
gpg --homedir "$SECUREGPGDIR" --send-keys "$KEY"
gpg --homedir "$SECUREGPGDIR" --export "$KEY" | gpg --import

pkill gpg-agent

umount "$SECUREHOME"
cryptsetup luksClose "/dev/mapper/$SECUREDEVICENAME"

Mit dem Skript kann folgendermassen ein Key signiert werden:

sudo ./securegpgsign 0x23FOOBA2 sde

Der Code ist auch in meinem Scripts Repository auf GitHub zu finden: securegpgsign.

Wir kein Devicename angegeben, wird sdc verwendet. Das Skript muss mit sudo aufgerufen werden, da das Einbinden des USB Sticks Rootrechte erfordert.

Links und weitere Informationen

Leave a Reply

Your email address will not be published. Required fields are marked *