Luks mit Gnupg-Card

UPDATE

Für das aktuelle Debian Stretch mit gnupg2 gibt es eine aktualisierte Anleitung: Luks mit Gnupg-Card unter Debian Stretch

Dieser Ansatz beruht im Wesentlichen auf der Anleitung von Peter Lebbing. Allerdings sind für die Unterstützung von Kartenlesern, für die gnupg keine eigene Unterstützung mitbringt, noch kleine Veränderungen nötig. Wir benötigen zusätzlich den pcscd-Dämon innerhalb der Initramdisk:

  • Kopieren zusätzlicher Bibliotheken in die Initramdisk
  • Starten des pcscd Dämons im decrypt_gnupg_sc Skript

Diese Anleitung setzt voraus, dass diejenigen, die sie anwenden, wissen was sie tun und die zugrundeliegenden Skripte verstehen. Es besteht die Gefahr, dass das System nicht mehr ohne weiteres gebootet werden kann. Anwender_innen sollten wissen, wie sie dann vorgehen müssen.

Diese Anleitung geht davon aus, dass bereits ein vollverschlüsseltes System auf Basis von Debian Wheezy existiert. Sie beinhaltet nicht die Beschreibung der grundsätzlichen Einrichtung der Festplattenverschlüsselung.

Voraussetzungen

Debian Jessie:

Das Vorgehen ist auch für Debian Jessie getestet. Damit es funktioniert muss in der initramdisk das Verzeichnis /var/run erstellt werden, weil der pcscd nicht mehr startet, wenn er kein PID schreiben kann.

  • Wir erstellen einen zufälligen Schlüssel, den wir als Key dem Luks-Heaer hinzufügen.
  • Dieser Key wird mit der GPG-Id einer Gnupg Card verschlüsselt und innerhalb der Initramdisk gespeichert
  • Beim Start des Computers wird ein Skript aufgerufen, das nach der PIN-Nummer der Gnupg Card fragt
  • Alternativ kann der Key zusätzlich mit einem symmetrischen Schlüssel (Passwort) verschlüsselt werden. Ist die Gnupg Card nicht zur Hand, kann dieser eingegeben werden.

Für die nächsten Schritte, die alle als Root ausgeführt werden, benötigen wir die Gnupg User-ID, mit der der Luks-Key verschlüsselt werden soll auch innerhalb des Gnupg-Setups von root. Ggf. muss also der Öffentliche Schlüssel in den Root-Schlüsselbund importiert werden.

Als User:

gpg --export --armor USER-ID > /tmp/key.asc

als Root:

gpg --import /tmp/key.asc

Die Skripte gehen davon dass unter:

/etc/keys/cryptkey.gpg

ein mit der gpg-ID der Gnupg-Card verschlüsselter Key liegt, der die Root-Partition entschlüsseln kann.

Weiterhin müssen unter /etc/keys die Dateien pubring.gpg (mit dem öffentlichen Schlüssel der verwendeten Gnupg ID) und secring.gpg existieren. Keine Sorge: In letzterer existiert kein geheimer Schlüssel sondern nur der Verweis auf die Gnupg Card.

Dass lässt sich z.B. folgendermaßen bewerkstelligen (GNUPG-ID muss durch die richtige ID ersetzt werden):

mkdir -m 700 /etc/keys
dd if=/dev/random bs=1 count=256 | gpg -e -o /etc/keys/cryptkey.gpg -r Gnupg-ID -ec
cd /root
mkfifo -m 700 keyfifo
gpg -d /etc/keys/cryptkey.gpg >keyfifo

In einem zweiten Terminal:

(„CRYPTDEVICE“ muss natürlich mit dem richtigen Device ersetzt werden.)

cd /root
cryptsetup luksAddKey /dev/CRYPTDEVICE keyfifo

Für die folgenden Kommandos muss die Gnupg Card als Root verwendet werden. Evtl. muss, wenn das ganze in einer User-X-Session stattfindet erst der scdaemon des Users beendet werden:

killall -9 scdaemon

In einem der beiden Terminals (das andere kann geschlossen werden) ({YOURKEYID} mit der gewünschten Gnupg-ID ersetzen):

rm keyfifo
gpg --export-options export-minimal --export {YOURKEYID} | gpg \
      --no-default-keyring --keyring /etc/keys/pubring.gpg \
      --secret-keyring /etc/keys/secring.gpg --import
gpg --no-default-keyring --keyring /etc/keys/pubring.gpg \
      --secret-keyring /etc/keys/secring.gpg --card-status

Vor der Anpassung sollte etwas folgendes in der /etc/crypttab stehen:

md1_crypt UUID=46ace282-0706-4fa3-9cb1-bd6f9aaba29d none luks

wir ersetzen alles ab none luks, so dass es in etwa folgendermaßen aussieht:

md1_crypt UUID=46ace282-0706-4fa3-9cb1-bd6f9aaba29d /etc/keys/cryptkey.gpg luks,keyscript=decrypt_gnupg_sc

Folgende Dateien sind nötig und müssen an die vorgesehenen Stellen kopiert werden:

  • /lib/cryptsetup/scripts/decrypt_gnupg_sc
  • /etc/initramfs-tools/hooks/cryptgnupg_sc

Für Cardreader ohne Pinpad, bei denen die PIN über die normale Tastatur eingegeben wird, sind weniger Binaries im initramfs erforderlich. Das Skript für Cardreader mit Pinpad funktioniert auch mit Cardreadern ohne Pinpad - allerdings darf der USB-Cardreader erst eingesteckt werden, wenn bereits nach dem Passwort gefragt wird.

FIXME: wir bräuchten eine Möglichkeit, Cardreader ohne Pinpad von solchen mit Pinpad zu unterscheiden.

Wird der Schlüssel „cryptkey.gpg“ zusätzlich zu den gpg-Ids auch noch mit einer symmetrischen Passphrase verschlüsselt (siehe oben), dann funktioniert die Freischaltung mit beiden Skripten auch mit der Eingabe der Passphrase über die Tastatur.

Das Skript decrypt_gnupg_sc wird später innerhalb der Initramdisk gestartet, startet dort den pcscd und fragt nach der PIN-Nummer der Karte bzw. nach einem Passwort für die zusätzlich vergebene symmetrische Verschlüsselung der gpg-Datei.

Die folgenden Skripte sind für Lesegeräte gedacht, die nicht vom internen ccid-Treiber des gnupg-Binaries unterstützt werden sondern einen laufenden pcsc Daemon benötigen. Falls der Kartenleser vom internen ccid unterstützt wird, können und müssen die entsprechenden Zeilen ausgelassen werden. Ob mit laufendem pcscd auch Kartenleser unterstützt werden, die diesen normalerweise nicht benötigen, habe ich noch nicht getestet.

Unter Stretch funktionieren die folgenden Skripte für Cardreader ohne Pinpad nicht mehr. Ein funktionierender Ansatz ist hier beschrieben: https://wiki.majic.rs/Openpgp/protecting_luks_decryption_key_in_debian_jessie_us/

/lib/cryptsetup/scripts/decrypt_gnupg_sc
#!/bin/sh
 
# quick hack for starting pcscd
# nur für Kartenleser benötigkt, die nicht von dem gnupg-internen ccid unterstützt werden
mkdir -p /var/run
pcscd &
 
decrypt_gpg () {
        echo "Performing GPG key decryption ..." >&2
        if ! /lib/cryptsetup/askpass \
                "Enter smartcard PIN or passphrase for key $1: " | \
                /usr/bin/gpg -q --batch --homedir "$(dirname $1)" \
                --trustdb-name /dev/null --passphrase-fd 0 --decrypt $1; then
                return 1
        fi
        return 0
}
 
if [ ! -x /usr/bin/gpg ]; then
        echo "$0: /usr/bin/gpg is not available" >&2
        exit 1
fi
 
if [ -z "$1" ]; then
        echo "$0: missing key as argument" >&2
        exit 1
fi
 
decrypt_gpg "$1"
exit $?

Das Starten des pcscd in Zeile 4 ist noch nicht sehr elegant, funktioniert aber.

Das Skript muss ausführbar sein:

chmod 755 /lib/cryptsetup/scripts/decrypt_gnupg_sc

Das Hook-Skript erledigt die Anpassungen in der Initramdisk und kopiert die nötigen binaries und Bibliotheken in die Initramdisk (u.a. gpg, pcscd):

/etc/initramfs-tools/hooks/cryptgnupg_sc
#!/bin/sh
 
set -e
 
PREREQ="cryptroot"
 
prereqs()
{
        echo "$PREREQ"
}
 
case $1 in
prereqs)
        prereqs
        exit 0
        ;;
esac
 
. /usr/share/initramfs-tools/hook-functions
 
# Hooks for loading Gnupg software and key into the initramfs
 
# Check whether cryptroot hook has installed decrypt_gnupg_sc script
if [ ! -x ${DESTDIR}/lib/cryptsetup/scripts/decrypt_gnupg_sc ] ; then
    exit 0
fi
 
# Install cryptroot key files into initramfs
keys=$(sed 's/^\(.*,\|\)key=//; s/,.*//' ${DESTDIR}/conf/conf.d/cryptroot)
 
if [ "${keys}" != "none" ]; then
    if [ -z "${keys}" ]; then
        echo "$0: Missing key files in ${DESTDIR}/conf/conf.d/cryptroot" >&2
        cat ${DESTDIR}/conf/conf.d/cryptroot >&2
        exit 1
    fi
    for key in ${keys} ; do
        keydir=$(dirname ${key})
        echo "WARNING: GnuPG key $key is copied to initramfs" >&2
        echo "WARNING: GnuPG secret keyring ${keydir}/secring.gpg is copied" \
             "to initramfs" >&2
        if [ ! -d ${DESTDIR}/${keydir} ] ; then
            mkdir -p ${DESTDIR}/${keydir}
        fi
        chmod 700 ${DESTDIR}/${keydir}
        cp -p ${key} ${DESTDIR}/${key}
        cp -p ${keydir}/pubring.gpg ${DESTDIR}/${keydir}
        cp -p ${keydir}/secring.gpg ${DESTDIR}/${keydir}
        if [ -e ${keydir}/gpg.conf ] ; then
            cp -p ${keydir}/gpg.conf ${DESTDIR}/${keydir}
        fi
    done
fi
 
# Install gnupg software
copy_exec /usr/bin/gpg
 
# some more libs for pcscd
# nur für Kartenleser benötigkt, die nicht von dem gnupg-internen ccid unterstützt werden
copy_exec /usr/sbin/pcscd
copy_exec /usr/lib/pcsc/drivers/serial/libccidtwin.so
copy_exec /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Linux/libccid.so
copy_exec /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist
copy_exec /etc/libccid_Info.plist
if uname -r | grep -q amd64; then
        copy_exec /usr/lib/x86_64-linux-gnu/libpcsclite.so.1.0.0
        copy_exec /lib/x86_64-linux-gnu/libgcc_s.so.1
else
        copy_exec /usr/lib/i386-linux-gnu/libpcsclite.so.1.0.0
        copy_exec /lib/i386-linux-gnu/libgcc_s.so.1
fi
exit 0

Achtung: das Skript funktioniert für i386 und amd64 Architekturen. Für andere Architekturen muss es entsprechend angepasst werden.

Die copy_exec Funktion aus /usr/share/initramfs-tools/hook-functions ist eigentlich für Binaries gedacht, um auch abhängige Bibliotheken zu kopieren. Das funktioniert so auch mit anderen Dateien, ist aber vermutlich nicht dafür gedacht.

Die nötigen Bibliotheken stecken in den Debian-Packeten libccid, libpcsclite1 und libgcc1.

Auch dieses Skript muss ausführbar sein:

chmod 755 /etc/initramfs-tools/hooks/cryptgnupg_sc

Für Kartenleser mit Pinpad benötigen wir gnupg2. Das Initramfs wird dadurch auch entsprechend größer: ~ 20 MB.

Achtung: Die gnupg2-Versionen aus Debian Wheezy sind zu alt. Die version 2.0.25 aus wheezy-backports funktioniert aber.

Am Anfang des Skripts wird eine kleine Abfrage gemacht, ob ein Kartenleser existiert. Wenn nicht, fragt das Skript nach der Passphrase. Diese Unterscheidung ist nötig, weil „askpass“ immer auf eine Eingabebestätigung wartet.

Wir können diesen Umstand ausnutzen, um auch Kartenleser ohne Pinpad zu nutzen. Wenn der Kartenleser erst eingesteckt wird, wenn das Skript sich schon in der Schleife mit „askpass“ befindet, sollte es auch mit der Karte und der Eingabe der PIN über die Tastatur funktionieren.

/lib/cryptsetup/scripts/decrypt_gnupg_sc
#!/bin/sh
 
# quick hack for starting pcscd
mkdir -p /var/run
pcscd &
 
decrypt_gpg () {
        # we check for attachted cardreader
        # cardreaders with pinpad: they have to be attached before booting
        # for cardreaders without pinpad: just attach them later, if the script already
        # asks for Passphrase or PIN
        if gpg2 --card-status > /dev/null 2>&1 && sleep 2; then
                echo "Please use the pinpad of your cardreader for PIN entry." >&2
                if ! /usr/bin/gpg2 --homedir "$(dirname $1)" \
                        --trustdb-name /dev/null --decrypt $1; then
                        return 1
                fi
                return 0
        else
                echo "Performing GPG key decryption ..." >&2
                if ! /lib/cryptsetup/askpass \
                        "Enter passphrase for key $1, or PIN for your cardreader: " | \
                        /usr/bin/gpg -q --batch --homedir "$(dirname $1)" \
                        --trustdb-name /dev/null --passphrase-fd 0 --decrypt $1; then
                        return 1
                fi
                return 0
        fi
}
 
if [ ! -x /usr/bin/gpg2 ]; then
        echo "$0: /usr/bin/gpg2 is not available" >&2
        exit 1
fi
 
if [ -z "$1" ]; then
        echo "$0: missing key as argument" >&2
        exit 1
fi
 
decrypt_gpg "$1"
exit $?
/etc/initramfs-tools/hooks/cryptgnupg_sc
#!/bin/sh
 
set -e
 
PREREQ="cryptroot"
 
prereqs()
{
        echo "$PREREQ"
}
 
case $1 in
prereqs)
        prereqs
        exit 0
        ;;
esac
 
. /usr/share/initramfs-tools/hook-functions
 
# Hooks for loading Gnupg software and key into the initramfs
 
# Check whether cryptroot hook has installed decrypt_gnupg_sc script
if [ ! -x ${DESTDIR}/lib/cryptsetup/scripts/decrypt_gnupg_sc ] ; then
    exit 0
fi
 
# Install cryptroot key files into initramfs
keys=$(sed 's/^\(.*,\|\)key=//; s/,.*//' ${DESTDIR}/conf/conf.d/cryptroot)
 
if [ "${keys}" != "none" ]; then
    if [ -z "${keys}" ]; then
        echo "$0: Missing key files in ${DESTDIR}/conf/conf.d/cryptroot" >&2
        cat ${DESTDIR}/conf/conf.d/cryptroot >&2
        exit 1
    fi
    for key in ${keys} ; do
        keydir=$(dirname ${key})
        echo "WARNING: GnuPG key $key is copied to initramfs" >&2
        echo "WARNING: GnuPG secret keyring ${keydir}/secring.gpg is copied" \
             "to initramfs" >&2
        if [ ! -d ${DESTDIR}/${keydir} ] ; then
            mkdir -p ${DESTDIR}/${keydir}
        fi
        chmod 700 ${DESTDIR}/${keydir}
        cp -p ${key} ${DESTDIR}/${key}
        cp -p ${keydir}/pubring.gpg ${DESTDIR}/${keydir}
        cp -p ${keydir}/secring.gpg ${DESTDIR}/${keydir}
        if [ -e ${keydir}/gpg.conf ] ; then
            cp -p ${keydir}/gpg.conf ${DESTDIR}/${keydir}
        fi
    done
fi
 
# Install gnupg software
copy_exec /usr/bin/gpg2
copy_exec /usr/bin/gpg
copy_exec /usr/bin/gpg-agent
 
 
# some more libs for pcscd
copy_exec /usr/sbin/pcscd
copy_exec /usr/lib/pcsc/drivers/serial/libccidtwin.so
copy_exec /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Linux/libccid.so
copy_exec /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist
copy_exec /etc/libccid_Info.plist
if uname -r | grep -q amd64; then
        copy_exec /usr/lib/x86_64-linux-gnu/libpcsclite.so.1.0.0
        copy_exec /lib/x86_64-linux-gnu/libgcc_s.so.1
else
        copy_exec /usr/lib/i386-linux-gnu/libpcsclite.so.1.0.0
        copy_exec /lib/i386-linux-gnu/libgcc_s.so.1
fi
 
# we need some more stuff from gnupg2
copy_exec /usr/lib/gnupg2/gnupg-pcsc-wrapper
copy_exec /usr/lib/gnupg2/scdaemon
copy_exec /usr/bin/pinentry
 
exit 0

Jetzt muss noch die Initramdisk neu erstellt werden. Vorher ist dringend geraten, eine Kopie der Initramdisk zu erstellen, mit der gebootet werden kann, falls das über die Gnupg Card aus irgendeinem Grund nicht funktioniert.

Z.B.

cp initrd.img-3.2.0-4-amd64 initrd.img-3.2.0-4-amd64-orig

Dann kann im Fall des Falles der Grub-Eintrag editiert werden. (Funktioniert einfach, indem beim Booten „e“ auf dem Grub-Eintrag gedrückt wird. Jetzt muss nur die Zeile mit der initrd gesucht werden und ein „-orig“ angehängt werden.) Dann bootet das System wie gewohnt. Das erspart einen den umständlicheren Einsatz eines Live-Rettungs-Systems.

Wir können jetzt aber unsere Initramdisk mit

update-initramfs -u

neu erstellen.

Der Output sollte in etwas so aussehen:

update-initramfs: Generating /boot/initrd.img-3.2.0-4-686-pae
WARNING: GnuPG key /etc/keys/cryptkey.gpg is copied to initramfs
WARNING: GnuPG secret keyring /etc/keys/secring.gpg is copied to initramfs
WARNING: GnuPG key /etc/keys/cryptkey.gpg is copied to initramfs
WARNING: GnuPG secret keyring /etc/keys/secring.gpg is copied to initramfs

Wenn Fehlermeldungen auftauchen, ist etwas schief gelaufen. Dann sollte vor einem Reboot unbedingt der Fehler gefunden werden, bzw. die Änderungen rückgängig gemacht werden. (Hook-Skript löschen und Initramdisk neu erstellen).

Ein Reboot des Systems zeigt, ob es geklappt hat.

Dieser Artikel steht unter der Creative Commons (BY-SA) Linzenz und darf unter gleichen Bedingungen weiter gegeben werden.

Weitere Ansätze zur Nutzung der Gnupg Karte mit Luks finden sich auf folgenden Seiten:

Cookies helfen bei der Bereitstellung von Inhalten. Durch die Nutzung dieser Seiten erklären Sie sich damit einverstanden, dass Cookies auf Ihrem Rechner gespeichert werden. Weitere Information