Skip to content

Commit

Permalink
rm: linux-disk-encryption: document re-encryption
Browse files Browse the repository at this point in the history
Document LUKS2 re-encryption and PKCS#11 emulation.

Signed-off-by: Jorge Ramirez-Ortiz <jorge@foundries.io>
  • Loading branch information
ldts committed Nov 1, 2023
1 parent ee013fc commit 182b37f
Showing 1 changed file with 275 additions and 30 deletions.
305 changes: 275 additions & 30 deletions source/reference-manual/linux/linux-disk-encryption.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,44 @@
Disk Encryption Support
=======================

LmP currently supports encrypting the disk used by the root file system
on first boot, as a way to guarantee a unique LUKS2 master key per device.
To enable a more secure deployment of systems before manufacturing can

Check warning on line 6 in source/reference-manual/linux/linux-disk-encryption.rst

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Fio-docs.sentence-length] Aim for sentences no longer than 25 words Raw Output: {"message": "[Fio-docs.sentence-length] Aim for sentences no longer than 25 words", "location": {"path": "source/reference-manual/linux/linux-disk-encryption.rst", "range": {"start": {"line": 6, "column": 1}}}, "severity": "INFO"}
provision the targets, LmP builds a password encrypted root file system
during image creation in CI.

On the first boot - during early boot in initramfs - this password is

Check warning on line 10 in source/reference-manual/linux/linux-disk-encryption.rst

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Fio-docs.sentence-length] Aim for sentences no longer than 25 words Raw Output: {"message": "[Fio-docs.sentence-length] Aim for sentences no longer than 25 words", "location": {"path": "source/reference-manual/linux/linux-disk-encryption.rst", "range": {"start": {"line": 10, "column": 1}}}, "severity": "INFO"}

Check warning on line 10 in source/reference-manual/linux/linux-disk-encryption.rst

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Fio-docs.em-dash] Did you mean to you use an em dash '—'? Raw Output: {"message": "[Fio-docs.em-dash] Did you mean to you use an em dash '—'?", "location": {"path": "source/reference-manual/linux/linux-disk-encryption.rst", "range": {"start": {"line": 10, "column": 18}}}, "severity": "WARNING"}

Check warning on line 10 in source/reference-manual/linux/linux-disk-encryption.rst

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Fio-docs.em-dash] Did you mean to you use an em dash '—'? Raw Output: {"message": "[Fio-docs.em-dash] Did you mean to you use an em dash '—'?", "location": {"path": "source/reference-manual/linux/linux-disk-encryption.rst", "range": {"start": {"line": 10, "column": 51}}}, "severity": "WARNING"}
discarded and a new key encryption key (KEK) is enrolled via systemd
using either a TPM 2.0 or a PKCS#11 based device.

Also at this moment, LmP initiates the rootfs online disk `re-encryption`_
and allows the system to continue booting.

As part of the normal boot sequence, a systemd service resumes the
re-encryption process in a non-blocking way. On completion the service
also creates a backup of the LUKS2 header. This backup image is stored
in the primary partition and shall allow booting systems where their
disk headers might have been damaged.

.. note::

If the system is restarted before the non-blocking re-encryption

Check warning on line 25 in source/reference-manual/linux/linux-disk-encryption.rst

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Fio-docs.sentence-length] Aim for sentences no longer than 25 words Raw Output: {"message": "[Fio-docs.sentence-length] Aim for sentences no longer than 25 words", "location": {"path": "source/reference-manual/linux/linux-disk-encryption.rst", "range": {"start": {"line": 25, "column": 4}}}, "severity": "INFO"}
service has completed, the next boot will be **blocked in initramfs**
until the rootfs has been fully encrypted.

The effort for creating an encrypted root file system during image creation
in CI (and required logic for online re-encryption during first boot) can be
tracked at https://github.com/foundriesio/meta-lmp/pull/868.

Prerequisites
-------------

As the process for decrypting the disk needs to be unattended, LmP requires
either PKCS#11 (e.g. OP-TEE with RPMB as secure storage) or TPM 2.0 to be
available by the target hardware, as they can be leveraged for securely
storing the Key Encryption Key (KEK) used for later decrypting the disk during
the boot process (via LUKS2 tokens, leveraging systemd-pkcs11 or systemd-tpm2,
see `systemd-cryptenroll`_ for more information).
As the process for encrypting and decrypting the disk needs to be

Check warning on line 33 in source/reference-manual/linux/linux-disk-encryption.rst

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Fio-docs.sentence-length] Aim for sentences no longer than 25 words Raw Output: {"message": "[Fio-docs.sentence-length] Aim for sentences no longer than 25 words", "location": {"path": "source/reference-manual/linux/linux-disk-encryption.rst", "range": {"start": {"line": 33, "column": 1}}}, "severity": "INFO"}
unattended, LmP requires either PKCS#11 (e.g. OP-TEE with RPMB as secure
storage) or TPM 2.0 to be available by the target hardware, as they can
be leveraged for securely storing the Key Encryption Key (KEK) used for
later decrypting the disk during the boot process (via LUKS2 tokens,
leveraging **systemd-pkcs11** or **systemd-tpm2**, see `systemd-cryptenroll`_
for more information).

For better security, TPM 2.0 support also requires UEFI secure boot to be
enabled, as the key is bound to the Platform Configuration Register (PCR) 7,
which tracks the secure boot state of the machine.
which tracks *the secure boot state of the machine*.

Enabling Support for Disk Encryption
------------------------------------
Expand Down Expand Up @@ -72,22 +90,8 @@ required. As an example, iMX8-based devices should use
This is not required with UEFI-based systems as systemd is capable of
automatically identifying and mounting the ESP partition during boot.

Implementation Details for OP-TEE PKCS#11 Support
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A dedicated slot is required to avoid conflicts with the PKCS#11 token slot
normally used by ``aktualizr-lite``. This dedicated slot is currently hardcoded
to slot 1, with the label ``lmp``.

During the encryption process the token slot is initialized and a RSA 2048 key
is generated, which is later used by `systemd-cryptenroll`_.

Make sure to **not** erase the token slot or the key during the lifetime of the
image, otherwise the system will fail to boot (a recovery key can be created and
provided manually if required, but it won't be an unattended boot).

Testing TPM 2.0 Support With Qemu (x86) and swtpm
-------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

It is possible to test the disk encryption support with TPM 2.0 with Qemu and
`swtpm`_.
Expand All @@ -101,7 +105,7 @@ Make sure LUKS support is enabled for your x86 target:
Then make sure to enroll the :ref:`UEFI Secure Boot Certificates <ref-secure-boot-uefi>`
to enable secure boot support. This is required as the LUKS2 TPM 2.0 token
leverages PCR 7, which tracks the secure boot state.
leverages **PCR 7**, which tracks the secure boot state.

Now install ``swtpm`` in the host machine (if not already installed), and start the ``swtpm``
daemon, which will be later consumed by Qemu and act as the hardware TPM.
Expand Down Expand Up @@ -159,14 +163,14 @@ Verify that LUKS2 is using the TPM 2.0 based systemd token for encryption:
Label: otaroot
Subsystem: (no subsystem)
Flags: (no flags)
Data segments:
0: crypt
offset: 16777216 [bytes]
length: (whole device)
cipher: aes-xts-plain64
sector: 512 [bytes]
Keyslots:
1: luks2
Key: 512 bits
Expand Down Expand Up @@ -216,6 +220,247 @@ Verify that LUKS2 is using the TPM 2.0 based systemd token for encryption:
Digest: 5c 30 5b f3 59 db fe 6a 71 c4 9a a0 2d 22 cf 6b
18 e7 cc 8d 6a 44 c9 67 97 f8 34 80 96 69 53 7b
.. note::

As long as the TPM2 emulation storage is not deleted, you will be
able to reboot your QEMU image since the key will persist.


Implementation Details for OP-TEE PKCS#11 Support
-------------------------------------------------

A dedicated slot is required to avoid conflicts with the PKCS#11 token slot
normally used by ``aktualizr-lite``. This dedicated slot is currently hardcoded
to **slot 1**, with the label ``lmp``.

During the encryption process the token slot is initialized and a **RSA 2048** key
is generated, which is later used by `systemd-cryptenroll`_.

Make sure to **NOT** erase the token slot or the key during the lifetime of the

Check warning on line 239 in source/reference-manual/linux/linux-disk-encryption.rst

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Fio-docs.sentence-length] Aim for sentences no longer than 25 words Raw Output: {"message": "[Fio-docs.sentence-length] Aim for sentences no longer than 25 words", "location": {"path": "source/reference-manual/linux/linux-disk-encryption.rst", "range": {"start": {"line": 239, "column": 1}}}, "severity": "INFO"}
image, otherwise the system will fail to boot (a recovery key can be created and
provided manually if required, but it won't be an unattended boot).

Check warning on line 241 in source/reference-manual/linux/linux-disk-encryption.rst

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Fio-docs.Contractions] Avoid Contractions: Use 'will not' not 'won't'. Raw Output: {"message": "[Fio-docs.Contractions] Avoid Contractions: Use 'will not' not 'won't'.", "location": {"path": "source/reference-manual/linux/linux-disk-encryption.rst", "range": {"start": {"line": 241, "column": 39}}}, "severity": "WARNING"}


Testing PKCS#11 Support With Qemu (arm64)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Make sure LUKS support is enabled for your qemuarm64-secureboot target:

.. code-block:: console
$ cat meta-subscriber-overrides/conf/machine/include/lmp-factory-custom.inc
DISTRO_FEATURES:append:qemuarm64-secureboot = " luks"
Run Qemu but be aware that trying to use over 2GB of memory might cause

Check warning on line 255 in source/reference-manual/linux/linux-disk-encryption.rst

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Fio-docs.sentence-length] Aim for sentences no longer than 25 words Raw Output: {"message": "[Fio-docs.sentence-length] Aim for sentences no longer than 25 words", "location": {"path": "source/reference-manual/linux/linux-disk-encryption.rst", "range": {"start": {"line": 255, "column": 1}}}, "severity": "INFO"}
the OP-TEE emulation not to boot so dont be tempted. :

.. code-block:: console
$ qemu-system-aarch64 -m 2048 -cpu cortex-a57 -no-acpi -bios flash.bin \
-device virtio-net-device,netdev=net0,mac=52:54:00:12:35:02 -device virtio-serial-device \
-drive id=disk0,file=lmp-console-image-qemuarm64-secureboot.wic,if=none,format=raw \
-device virtio-blk-device,drive=disk0 -netdev user,id=net0,hostfwd=tcp::2222-:22 \
-object rng-random,filename=/dev/urandom,id=rng0 -device virtio-rng-pci,rng=rng0 \
-chardev null,id=virtcon -machine virt,secure=on -nographic
During boot you will see the following:

.. code-block:: none
[ 1.932467] Freeing unused kernel memory: 4736K
[ 1.933323] Run /init as init process
Starting version 250.5+
[ 53.995060] e2fsck: otaroot: clean, 7841/136880 files, 79834/156064 blocks
Enrolling LUKS2 keyslot based on pkcs11 token
Token successfully initialized
User PIN successfully initialized
Key pair generated:
Private Key Object; RSA
label: luks
ID: 9d
Usage: decrypt, sign
Access: sensitive, always sensitive, never extractable, local
Public Key Object; RSA 2048 bits
label: luks
ID: 9d
Usage: encrypt, verify
Access: local
Engine "pkcs11" set.
Created certificate:
7Certificate Object; type = X.509 cert
label: luks
subject: DN: CN=LmP
ID: 9d
Successfully logged into security token 'lmp' via protected authentication path.
New PKCS#11 token enrolled as key slot 0.
Wiped slot 31.
Successfully logged into security token 'lmp' via protected authentication path.
Successfully decrypted key with security token.
[...]
[ OK ] Reached target Basic System.
Starting D-Bus System Message Bus...
Starting Check and fix an … store of the docker daemon...
Starting IPv6 Packet Filtering Framework...
Starting IPv4 Packet Filtering Framework...
Starting Online LUKS2 disk re-encryption...
Starting User Login Management...
[ OK ] Started TEE Supplicant.
[ OK ] Started Network Name Resolution.
[ OK ] Finished IPv6 Packet Filtering Framework.
[ OK ] Finished IPv4 Packet Filtering Framework.
[ OK ] Starting Network Manager Script Dispatcher Service...
[ OK ] Started Network Manager Script Dispatcher Service.
Linux-microPlatform 4.0.11 qemuarm64-secureboot -
qemuarm64-secureboot login: fio
Password:
fio@qemuarm64-secureboot:~$
[ OK ] Finished Online LUKS2 disk re-encryption.
Starting Resize root filesystem to fit available disk space...
[ 210.434491] EXT4-fs (dm-0): resizing filesystem from 156064 to 160161 blocks
[ 210.448134] EXT4-fs (dm-0): resized filesystem to 160161
[ OK ] Finished Resize root filesystem to fit available disk space.
After the service has finished, you can inspect the volume. First list
the block devices:

.. code-block:: none
fio@qemuarm64-secureboot:~$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
zram0 251:0 0 0B 0 disk
vda 253:0 0 925.6M 0 disk
|-vda1 253:1 0 78M 0 part /var/rootdirs/mnt/boot
|-vda2 253:2 0 200M 0 part /boot
`-vda3 253:3 0 641.6M 0 part
`-vda3_crypt 252:0 0 625.6M 0 crypt /var
/usr
/
/sysroot
Then inspect the encrypted one:

.. code-block:: none
fio@qemuarm64-secureboot:~$ sudo cryptsetup luksDump /dev/vda3
Password:
LUKS header information
Version: 2
Epoch: 99
Metadata area: 16384 [bytes]
Keyslots area: 16744448 [bytes]
UUID: 06be9f40-ac4f-4301-ad33-e566def6023d
Label: otaroot
Subsystem: (no subsystem)
Flags: (no flags)
Data segments:
0: crypt
offset: 16777216 [bytes]
length: (whole device)
cipher: aes-xts-plain64
sector: 512 [bytes]
Keyslots:
1: luks2
Key: 512 bits
Priority: normal
Cipher: aes-xts-plain64
Cipher key: 512 bits
PBKDF: pbkdf2
Hash: sha512
Iterations: 1000
Salt: a2 76 b4 61 3b c6 79 02 1a c1 23 89 02 ca 02 8f
f3 82 ec e6 c4 b0 6a c7 4a 4b 99 5e e6 92 c0 88
AF stripes: 4000
AF hash: sha512
Area offset:32768 [bytes]
Area length:258048 [bytes]
Digest ID: 1
Tokens:
0: systemd-pkcs11
pkcs11-uri: pkcs11:token=lmp;object=luks
pkcs11-key: 38 49 ce f7 3e e9 dc fc 66 3d b8 13 90 ec ec 29
99 73 5d 47 6a cb d0 fc 6c ab 1c a7 26 a8 08 7e
46 b3 5d 15 f5 01 a9 e7 e6 d2 80 72 15 14 0d 0b
61 85 fe ee 1f f8 f0 04 26 c8 46 31 83 52 cc 37
44 d7 2a 83 7d 5a d9 44 a3 90 d0 f5 ff f2 9d e3
6f 09 4b 2c 79 5e df e3 b0 f7 df b4 b2 8c 0b 78
0a 4a 31 c1 d1 63 bb 54 a3 ca c9 a9 a3 88 bc ec
96 68 25 26 75 b3 44 3d 9b ee bc a4 73 a5 e2 b3
f2 5e a3 74 29 32 7a 46 b2 af 55 cf 48 3d b6 ea
4e d0 ca 0c da 06 f1 4e 33 23 73 be bb b0 c0 e1
ab bf 7a 2d f3 d7 7a be 5c 01 e5 d6 ab 43 33 91
48 e7 14 77 61 1c b9 c0 2c 6a 47 36 4c 1f a1 81
39 8c 5b 56 43 fa 86 33 7f 8d ec ee cf 74 1a 3a
43 69 6d bf 3b 70 70 ea 4b f7 02 a0 99 c0 55 02
49 16 14 00 45 da 78 da b9 5e 34 17 65 1b 3b c3
78 26 64 60 bf fe da 11 a0 3b 7a f9 0f 9e 93 8f
Keyslot: 1
Digests:
1: pbkdf2
Hash: sha512
Iterations: 1000
Salt: a6 10 c3 0d 89 22 c4 67 32 c1 c4 49 31 6f 05 10
4a f6 3d bd 7f 26 7a ba 9e 74 54 0b 5f da 54 34
Digest: 58 da 0f b2 ec d5 0d 5d 3d 99 15 85 85 ab e5 40
41 14 9c 57 6a 16 02 08 5d 8f 2a 18 ca 77 2d 7b
e1 be 92 d4 0a 49 f1 f1 77 48 c3 c1 27 35 57 ea
68 47 60 20 15 a1 a2 80 11 c5 dd 8e c7 93 c4 80
We could also inspect the PKCS#11 slot created by OP-TEE to store the
RSA-2048 key we mentioned earlier:

.. code-block:: none
root@qemuarm64-secureboot:/var/rootdirs/home/fio# pkcs11-tool --module /usr/lib/libckteec.so.0 --list-token-slots
Available slots:
Slot 0 (0x0): 94e9ab89-4c43-56ea-8b35-45dc07226830
token state: uninitialized
Slot 1 (0x1): 94e9ab89-4c43-56ea-8b35-45dc07226830
token label : lmp
token manufacturer : Linaro
token model : OP-TEE TA
token flags : login required, PIN pad present, rng, token initialized, PIN initialized
hardware version : 0.0
firmware version : 0.1
serial num : 0000000000000001
pin min/max : 4/128
Slot 2 (0x2): 94e9ab89-4c43-56ea-8b35-45dc07226830
token state: uninitialized
.. note::

The OP-TEE PKCS#11 secure storage emulation will **NOT** persist across
reboots. Since the rootfs was encrypted, the system will fail to
mount the rootfs on the next boot.

This is the error that you should expect were you to reboot:

.. code-block :: none
[ 1.776260] registered taskstats version 1
[ 1.776628] Loading compiled-in X.509 certificates
[ 1.879079] Loaded X.509 cert 'Default insecure key from Factory II: 1b2327c0b75d0bc1e4914c8195bbf053629b8abb'
[ 1.902679] uart-pl011 9000000.pl011: no DMA platform data
[ 1.937637] Freeing unused kernel memory: 4736K
[ 1.938472] Run /init as init process
Starting version 250.5+
No slot with token named "lmp" found
PKCS11 certificate not found!
.. _re-encryption:
https://man7.org/linux/man-pages/man8/cryptsetup-reencrypt.8.html

.. _systemd-cryptenroll:
https://www.freedesktop.org/software/systemd/man/systemd-cryptenroll.html

Expand Down

0 comments on commit 182b37f

Please sign in to comment.