diff mbox series

[isar-cip-core,RFC,5/5] Add initramfs hook to encrypt a partition

Message ID 20230130150204.697758-6-Quirin.Gylstorff@siemens.com (mailing list archive)
State Superseded
Headers show
Series Encrypt Partition in initramfs | expand

Commit Message

Quirin Gylstorff Jan. 30, 2023, 3:02 p.m. UTC
From: Quirin Gylstorff <quirin.gylstorff@siemens.com>

This creates a new luks encrypted ext4 partition with a the
key stored in the tpm2.

The initial key is randomly generated and removed from the
LUKS partition. Therefore a new key cannot be added by the user
and if the LUKS header is corrupted the data is no longer readable.

Signed-off-by: Quirin Gylstorff <quirin.gylstorff@siemens.com>
---
 kas/opt/tpm.yml                               |  2 +
 .../files/create_crypt_partition.script       | 96 +++++++++++++++++++
 .../files/crypt-partition.env.tmpl            |  1 +
 .../initramfs-crypt-hook/files/crypt.hook     | 42 ++++++++
 .../initramfs-crypt-hook_0.1.bb               | 37 +++++++
 5 files changed, 178 insertions(+)
 create mode 100644 recipes-initramfs/initramfs-crypt-hook/files/create_crypt_partition.script
 create mode 100644 recipes-initramfs/initramfs-crypt-hook/files/crypt-partition.env.tmpl
 create mode 100644 recipes-initramfs/initramfs-crypt-hook/files/crypt.hook
 create mode 100644 recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.1.bb

Comments

Jan Kiszka Jan. 31, 2023, 1:32 p.m. UTC | #1
On 30.01.23 16:02, Quirin Gylstorff wrote:
> From: Quirin Gylstorff <quirin.gylstorff@siemens.com>
> 
> This creates a new luks encrypted ext4 partition with a the
> key stored in the tpm2.

Again my question: Why a new partition, and what do we do with the
critical data on /home and the overlay(s)? Why not demonstrating their
protection?

> 
> The initial key is randomly generated and removed from the
> LUKS partition. Therefore a new key cannot be added by the user
> and if the LUKS header is corrupted the data is no longer readable.
> 
> Signed-off-by: Quirin Gylstorff <quirin.gylstorff@siemens.com>
> ---
>  kas/opt/tpm.yml                               |  2 +
>  .../files/create_crypt_partition.script       | 96 +++++++++++++++++++
>  .../files/crypt-partition.env.tmpl            |  1 +
>  .../initramfs-crypt-hook/files/crypt.hook     | 42 ++++++++
>  .../initramfs-crypt-hook_0.1.bb               | 37 +++++++
>  5 files changed, 178 insertions(+)
>  create mode 100644 recipes-initramfs/initramfs-crypt-hook/files/create_crypt_partition.script
>  create mode 100644 recipes-initramfs/initramfs-crypt-hook/files/crypt-partition.env.tmpl
>  create mode 100644 recipes-initramfs/initramfs-crypt-hook/files/crypt.hook
>  create mode 100644 recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.1.bb
> 
> diff --git a/kas/opt/tpm.yml b/kas/opt/tpm.yml
> index 03e8e47..a77a2be 100644
> --- a/kas/opt/tpm.yml
> +++ b/kas/opt/tpm.yml
> @@ -16,3 +16,5 @@ local_conf_header:
>    systemd-cryptenroll: |
>      DISTRO_APT_SOURCES_append_bullseye = " conf/distro/debian-bullseye-backports.list"
>      DISTRO_APT_PREFERENCES_append_bullseye = " conf/distro/preferences.bullseye-backports.tpm.conf"
> +  image-option-tpm: |
> +    INITRAMFS_INSTALL += " initramfs-crypt-hook"
> diff --git a/recipes-initramfs/initramfs-crypt-hook/files/create_crypt_partition.script b/recipes-initramfs/initramfs-crypt-hook/files/create_crypt_partition.script
> new file mode 100644
> index 0000000..a30dc59
> --- /dev/null
> +++ b/recipes-initramfs/initramfs-crypt-hook/files/create_crypt_partition.script
> @@ -0,0 +1,96 @@
> +#!/bin/sh
> +#
> +# CIP Core, generic profile
> +#
> +# Copyright (c) Siemens AG, 2023
> +#
> +# Authors:
> +#  Quirin Gylstorff <quirin.gylstorff@siemens.com>
> +#
> +# SPDX-License-Identifier: MIT
> +prereqs()
> +{
> +    # Make sure that this script is run last in local-top
> +    local req
> +    for req in "${0%/*}"/*; do
> +        script="${req##*/}"
> +        if [ "$script" != "${0##*/}" ]; then
> +            printf '%s\n' "$script"
> +        fi
> +    done
> +}
> +case $1 in
> +prereqs)
> +    prereqs
> +    exit 0
> +    ;;
> +esac
> +
> +. /scripts/functions
> +
> +. /usr/share/crypt/crypt-partition.env
> +
> +# fixed tpm device or do we need to find it
> +tpm_device=/dev/tpmrm0
> +partition="$PARTITION"
> +partition_label=$(echo "$partition" | awk -F "/" '{print $NF}')
> +crypt_mount_name="encrypted_$partition_label"
> +decrypted_part=/dev/mapper/"$crypt_mount_name"
> +
> +if [ ! -e "$partition" ]; then
> +    panic "$partition does not exist!"
> +fi
> +
> +modprobe tpm_tis
> +modprobe tpm_crb
> +
> +if [ ! -e "$tpm_device" ]; then
> +    panic "tpm device '$tpm_device' does not exists - cannot create a encrypted device!"
> +fi
> +
> +# check if partition is already encrypted with systemd-tpm2
> +if /usr/sbin/cryptsetup luksDump --batch-mode "$partition" \
> +        | grep -q "systemd-tpm2"; then
> +    if ! /usr/lib/systemd/systemd-cryptsetup attach "$crypt_mount_name" \
> +         "$partition" - tpm2-device="$tpm_device"; then
> +        panic "Can't decrypt '$partition' !"
> +    fi
> +    return
> +fi
> +
> +# create random password for initial encryption
> +# this will be dropped after reboot
> +
> +tmp_key=/tmp/"$partition_label-lukskey"
> +openssl rand -base64 32 > "$tmp_key"
> +
> +/usr/sbin/cryptsetup luksFormat --batch-mode \
> +                     --type luks2 "$partition" < "$tmp_key"
> +
> +#check systemd version and export password if necessary
> +if [ -x /usr/bin/systemd-cryptenroll ]; then
> +    systemd_version=$(systemd-cryptenroll --version | \
> +                          awk -F " " 'NR==1{print $2 }')
> +    #check systemd version and export password if necessary
> +    if [ "$systemd_version" -ge "251" ]; then
> +        PASSWORD=$(cat "$tmp_key" )
> +        export PASSWORD
> +        /usr/bin/systemd-cryptenroll --tpm2-device="$tpm_device" \
> +                                     --tpm2-pcrs=7 "$partition"
> +        PASSWORD=
> +    else
> +       panic "Unknown systemd version: '$systemd_version'!"
> +   fi
> +fi
> +
> +wait_for_udev 10
> +
> +if ! /usr/lib/systemd/systemd-cryptsetup attach "$crypt_mount_name" \
> +     "$partition" - tpm2-device="$tpm_device"; then
> +    panic "Can't decrypt '$partition' !"
> +fi
> +
> +mke2fs -t ext4 "${decrypted_part}"
> +
> +# delete initial key
> +/usr/bin/systemd-cryptenroll "$partition" --wipe-slot=0
> diff --git a/recipes-initramfs/initramfs-crypt-hook/files/crypt-partition.env.tmpl b/recipes-initramfs/initramfs-crypt-hook/files/crypt-partition.env.tmpl
> new file mode 100644
> index 0000000..04c4123
> --- /dev/null
> +++ b/recipes-initramfs/initramfs-crypt-hook/files/crypt-partition.env.tmpl
> @@ -0,0 +1 @@
> +PARTITION=${CRYPT_PARTITION}
> diff --git a/recipes-initramfs/initramfs-crypt-hook/files/crypt.hook b/recipes-initramfs/initramfs-crypt-hook/files/crypt.hook
> new file mode 100644
> index 0000000..38fff49
> --- /dev/null
> +++ b/recipes-initramfs/initramfs-crypt-hook/files/crypt.hook
> @@ -0,0 +1,42 @@
> +#!/bin/sh
> +# Copyright (C) Siemens AG, 2020-2022
> +#
> +# SPDX-License-Identifier: MIT
> +
> +PREREQ=""
> +
> +prereqs()
> +{
> +     echo "$PREREQ"
> +}
> +
> +case $1 in
> +prereqs)
> +     prereqs
> +     exit 0
> +     ;;
> +esac
> +
> +. /usr/share/initramfs-tools/scripts/functions
> +. /usr/share/initramfs-tools/hook-functions
> +
> +manual_add_modules tpm
> +manual_add_modules tpm_tis_core
> +manual_add_modules tpm_tis
> +manual_add_modules tpm_crb
> +manual_add_modules dm_mod
> +manual_add_modules dm_crypt
> +
> +copy_exec /usr/bin/openssl
> +copy_exec /usr/sbin/mke2fs
> +copy_exec /usr/bin/grep
> +copy_exec /usr/bin/awk
> +copy_exec /usr/sbin/cryptsetup
> +copy_exec /usr/bin/systemd-cryptenroll
> +copy_exec /usr/lib/systemd/systemd-cryptsetup
> +
> +for _LIBRARY in /usr/lib/*/libtss2*; do
> +    copy_exec "$_LIBRARY"
> +done
> +
> +copy_file library /usr/share/crypt/crypt-partition.env /usr/share/crypt/crypt-partition.env
> diff --git a/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.1.bb b/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.1.bb
> new file mode 100644
> index 0000000..024ff68
> --- /dev/null
> +++ b/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.1.bb
> @@ -0,0 +1,37 @@
> +#
> +# CIP Core, generic profile
> +#
> +# Copyright (c) Siemens AG, 2020-2022
> +#
> +# Authors:
> +#  Quirin Gylstorff <quirin.gylstorff@siemens.com>
> +#
> +# SPDX-License-Identifier: MIT
> +
> +
> +inherit dpkg-raw
> +
> +DEBIAN_DEPENDS = "initramfs-tools, cryptsetup, systemd(>= 251), \
> +    awk, openssl,  libtss2-esys-3.0.2-0,  libtss2-rc0, libtss2-mu0, e2fsprogs"
> +
> +SRC_URI += "file://crypt.hook \
> +            file://create_crypt_partition.script \
> +    file://crypt-partition.env.tmpl"
> +
> +CRYPT_PARTITION ??= "/dev/disk/by-partlabel/crypt-data"
> +CRYPT_MOUNT_POINT ??= "/data"

This only supports a single encrypted partition, right? Why not
following the same pattern as for overlays?

> +
> +TEMPLATE_VARS = "CRYPT_PARTITION CRYPT_MOUNT_POINT"
> +TEMPLATE_FILES = "crypt-partition.env.tmpl"
> +
> +do_install[cleandirs] += " \
> +    ${D}/usr/share/initramfs-tools/hooks \
> +    ${D}/usr/share/crypt \
> +    ${D}/usr/share/initramfs-tools/scripts/local-top"
> +do_install() {
> +    install -m 0600 "${WORKDIR}/crypt-partition.env" "${D}/usr/share/crypt/crypt-partition.env"
> +    install -m 0755 "${WORKDIR}/create_crypt_partition.script" \
> +        "${D}/usr/share/initramfs-tools/scripts/local-top/crypt"
> +    install -m 0755 "${WORKDIR}/crypt.hook" \
> +        "${D}/usr/share/initramfs-tools/hooks/crypt"
> +}

Jan
diff mbox series

Patch

diff --git a/kas/opt/tpm.yml b/kas/opt/tpm.yml
index 03e8e47..a77a2be 100644
--- a/kas/opt/tpm.yml
+++ b/kas/opt/tpm.yml
@@ -16,3 +16,5 @@  local_conf_header:
   systemd-cryptenroll: |
     DISTRO_APT_SOURCES_append_bullseye = " conf/distro/debian-bullseye-backports.list"
     DISTRO_APT_PREFERENCES_append_bullseye = " conf/distro/preferences.bullseye-backports.tpm.conf"
+  image-option-tpm: |
+    INITRAMFS_INSTALL += " initramfs-crypt-hook"
diff --git a/recipes-initramfs/initramfs-crypt-hook/files/create_crypt_partition.script b/recipes-initramfs/initramfs-crypt-hook/files/create_crypt_partition.script
new file mode 100644
index 0000000..a30dc59
--- /dev/null
+++ b/recipes-initramfs/initramfs-crypt-hook/files/create_crypt_partition.script
@@ -0,0 +1,96 @@ 
+#!/bin/sh
+#
+# CIP Core, generic profile
+#
+# Copyright (c) Siemens AG, 2023
+#
+# Authors:
+#  Quirin Gylstorff <quirin.gylstorff@siemens.com>
+#
+# SPDX-License-Identifier: MIT
+prereqs()
+{
+    # Make sure that this script is run last in local-top
+    local req
+    for req in "${0%/*}"/*; do
+        script="${req##*/}"
+        if [ "$script" != "${0##*/}" ]; then
+            printf '%s\n' "$script"
+        fi
+    done
+}
+case $1 in
+prereqs)
+    prereqs
+    exit 0
+    ;;
+esac
+
+. /scripts/functions
+
+. /usr/share/crypt/crypt-partition.env
+
+# fixed tpm device or do we need to find it
+tpm_device=/dev/tpmrm0
+partition="$PARTITION"
+partition_label=$(echo "$partition" | awk -F "/" '{print $NF}')
+crypt_mount_name="encrypted_$partition_label"
+decrypted_part=/dev/mapper/"$crypt_mount_name"
+
+if [ ! -e "$partition" ]; then
+    panic "$partition does not exist!"
+fi
+
+modprobe tpm_tis
+modprobe tpm_crb
+
+if [ ! -e "$tpm_device" ]; then
+    panic "tpm device '$tpm_device' does not exists - cannot create a encrypted device!"
+fi
+
+# check if partition is already encrypted with systemd-tpm2
+if /usr/sbin/cryptsetup luksDump --batch-mode "$partition" \
+        | grep -q "systemd-tpm2"; then
+    if ! /usr/lib/systemd/systemd-cryptsetup attach "$crypt_mount_name" \
+         "$partition" - tpm2-device="$tpm_device"; then
+        panic "Can't decrypt '$partition' !"
+    fi
+    return
+fi
+
+# create random password for initial encryption
+# this will be dropped after reboot
+
+tmp_key=/tmp/"$partition_label-lukskey"
+openssl rand -base64 32 > "$tmp_key"
+
+/usr/sbin/cryptsetup luksFormat --batch-mode \
+                     --type luks2 "$partition" < "$tmp_key"
+
+#check systemd version and export password if necessary
+if [ -x /usr/bin/systemd-cryptenroll ]; then
+    systemd_version=$(systemd-cryptenroll --version | \
+                          awk -F " " 'NR==1{print $2 }')
+    #check systemd version and export password if necessary
+    if [ "$systemd_version" -ge "251" ]; then
+        PASSWORD=$(cat "$tmp_key" )
+        export PASSWORD
+        /usr/bin/systemd-cryptenroll --tpm2-device="$tpm_device" \
+                                     --tpm2-pcrs=7 "$partition"
+        PASSWORD=
+    else
+       panic "Unknown systemd version: '$systemd_version'!"
+   fi
+fi
+
+wait_for_udev 10
+
+if ! /usr/lib/systemd/systemd-cryptsetup attach "$crypt_mount_name" \
+     "$partition" - tpm2-device="$tpm_device"; then
+    panic "Can't decrypt '$partition' !"
+fi
+
+mke2fs -t ext4 "${decrypted_part}"
+
+# delete initial key
+/usr/bin/systemd-cryptenroll "$partition" --wipe-slot=0
diff --git a/recipes-initramfs/initramfs-crypt-hook/files/crypt-partition.env.tmpl b/recipes-initramfs/initramfs-crypt-hook/files/crypt-partition.env.tmpl
new file mode 100644
index 0000000..04c4123
--- /dev/null
+++ b/recipes-initramfs/initramfs-crypt-hook/files/crypt-partition.env.tmpl
@@ -0,0 +1 @@ 
+PARTITION=${CRYPT_PARTITION}
diff --git a/recipes-initramfs/initramfs-crypt-hook/files/crypt.hook b/recipes-initramfs/initramfs-crypt-hook/files/crypt.hook
new file mode 100644
index 0000000..38fff49
--- /dev/null
+++ b/recipes-initramfs/initramfs-crypt-hook/files/crypt.hook
@@ -0,0 +1,42 @@ 
+#!/bin/sh
+# Copyright (C) Siemens AG, 2020-2022
+#
+# SPDX-License-Identifier: MIT
+
+PREREQ=""
+
+prereqs()
+{
+     echo "$PREREQ"
+}
+
+case $1 in
+prereqs)
+     prereqs
+     exit 0
+     ;;
+esac
+
+. /usr/share/initramfs-tools/scripts/functions
+. /usr/share/initramfs-tools/hook-functions
+
+manual_add_modules tpm
+manual_add_modules tpm_tis_core
+manual_add_modules tpm_tis
+manual_add_modules tpm_crb
+manual_add_modules dm_mod
+manual_add_modules dm_crypt
+
+copy_exec /usr/bin/openssl
+copy_exec /usr/sbin/mke2fs
+copy_exec /usr/bin/grep
+copy_exec /usr/bin/awk
+copy_exec /usr/sbin/cryptsetup
+copy_exec /usr/bin/systemd-cryptenroll
+copy_exec /usr/lib/systemd/systemd-cryptsetup
+
+for _LIBRARY in /usr/lib/*/libtss2*; do
+    copy_exec "$_LIBRARY"
+done
+
+copy_file library /usr/share/crypt/crypt-partition.env /usr/share/crypt/crypt-partition.env
diff --git a/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.1.bb b/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.1.bb
new file mode 100644
index 0000000..024ff68
--- /dev/null
+++ b/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.1.bb
@@ -0,0 +1,37 @@ 
+#
+# CIP Core, generic profile
+#
+# Copyright (c) Siemens AG, 2020-2022
+#
+# Authors:
+#  Quirin Gylstorff <quirin.gylstorff@siemens.com>
+#
+# SPDX-License-Identifier: MIT
+
+
+inherit dpkg-raw
+
+DEBIAN_DEPENDS = "initramfs-tools, cryptsetup, systemd(>= 251), \
+    awk, openssl,  libtss2-esys-3.0.2-0,  libtss2-rc0, libtss2-mu0, e2fsprogs"
+
+SRC_URI += "file://crypt.hook \
+            file://create_crypt_partition.script \
+    file://crypt-partition.env.tmpl"
+
+CRYPT_PARTITION ??= "/dev/disk/by-partlabel/crypt-data"
+CRYPT_MOUNT_POINT ??= "/data"
+
+TEMPLATE_VARS = "CRYPT_PARTITION CRYPT_MOUNT_POINT"
+TEMPLATE_FILES = "crypt-partition.env.tmpl"
+
+do_install[cleandirs] += " \
+    ${D}/usr/share/initramfs-tools/hooks \
+    ${D}/usr/share/crypt \
+    ${D}/usr/share/initramfs-tools/scripts/local-top"
+do_install() {
+    install -m 0600 "${WORKDIR}/crypt-partition.env" "${D}/usr/share/crypt/crypt-partition.env"
+    install -m 0755 "${WORKDIR}/create_crypt_partition.script" \
+        "${D}/usr/share/initramfs-tools/scripts/local-top/crypt"
+    install -m 0755 "${WORKDIR}/crypt.hook" \
+        "${D}/usr/share/initramfs-tools/hooks/crypt"
+}