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 aa0289b
Showing 1 changed file with 305 additions and 32 deletions.
337 changes: 305 additions & 32 deletions source/reference-manual/linux/linux-disk-encryption.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,56 @@
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 enhance the security of system deployments before manufacturing
provisions the targets, LmP takes the following approach:

During the image creation process in CI, LmP constructs a symmetrically
encrypted root file system, which is locked/unlocked by a password.

Upon the initial boot, during the early boot phase in initramfs, the
password used for accessing the volume is discarded. Instead, a new Key
Encryption Key (KEK) is established using systemd. This KEK is enrolled
through either a TPM 2.0 or a PKCS#11 security token (or a smartcard)
that stores an RSA key pair. Subsequently, the system can unlock the
volume without requiring any user intervention.

Simultaneously, at this point, LmP triggers an online disk
`re-encryption`_ process for the rootfs and allows the system to continue
its boot sequence.

As part of the regular boot procedure, a systemd service resumes the
re-encryption process in a non-blocking manner. Upon completion of the
service, a backup of the LUKS2 header is additionally created. This

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": 64}}}, "severity": "INFO"}
backup image is stored in the primary partition and serves as a
safeguard, enabling the booting of systems in cases where their disk
headers may have been damaged.

..note::

If the system is restarted before the non-blocking re-encryption
service has finished, the subsequent boot will be **blocked in
initramfs** until the root file system 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).
To ensure that the disk encryption and decryption processes can be

Check warning on line 40 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": 40, "column": 1}}}, "severity": "INFO"}
carried out without human intervention, LmP mandates the presence of
either PKCS#11 (for instance, OP-TEE with RPMB serving as secure
storage) or TPM 2.0 on the target hardware.

Both of these types of devices can be utilized to securely store the Key

Check warning on line 45 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": 45, "column": 1}}}, "severity": "INFO"}
Encryption Key (KEK), which is used to unlock the disk during the boot
procedure. This is achieved through the use of LUKS2 tokens, making use
of either **systemd-pkcs11** or **systemd-tpm2** (refer to
`systemd-cryptenroll`_ for additional details).

For heightened security, support for TPM 2.0 also necessitates that UEFI
secure boot be enabled. This is because the unlock key is tied to the
Platform Configuration Register (PCR) 7, which monitors the **secure boot
state of the machine**.

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.

Enabling Support for Disk Encryption
------------------------------------
Expand Down Expand Up @@ -72,22 +102,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 +117,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 +175,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 +232,263 @@ 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
-------------------------------------------------

To prevent conflicts with the PKCS#11 token slot typically utilized by
``aktualizr-lite``, a dedicated slot is necessary. Currently, this
dedicated slot is set as **slot 1**, with the label ``lmp``.

Before initiating the re-encryption process, the PKCS#11 token slot is
initialized, and a new **RSA 2048** key is generated. This is a

Check warning on line 249 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": 249, "column": 55}}}, "severity": "INFO"}
requirement because LUKS necessitates that the security token contains
an RSA key pair for encrypting the randomly generated key that will be
used in the future to unlock the volume.

It is important to emphasize that the **encrypted key** is stored in the
LUKS JSON token header area. The RSA key from the token is exclusively
utilized by `systemd-cryptenroll`_ for generating the encrypted key.

Please ensure that you **DO NOT** erase the token slot or the key
throughout the lifespan of the image. Failure to follow this precaution
will result in the system's inability to boot because it won't be able

Check warning on line 260 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": 260, "column": 58}}}, "severity": "WARNING"}
to unlock the encrypted volume.

In the event of such a scenario, a recovery key can be created and
provided manually, but it won't support an unattended boot process.

Check warning on line 264 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": 264, "column": 27}}}, "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"
When running Qemu, please be cautious not to exceed 2GB of memory usage,

Check warning on line 278 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": 278, "column": 1}}}, "severity": "INFO"}
as attempting to use more than 2GB of memory may prevent the OP-TEE
emulation from successfully booting. So, it's advisable to stay within

Check warning on line 280 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 'it is' not 'it's'. Raw Output: {"message": "[Fio-docs.Contractions] Avoid Contractions: Use 'it is' not 'it's'.", "location": {"path": "source/reference-manual/linux/linux-disk-encryption.rst", "range": {"start": {"line": 280, "column": 42}}}, "severity": "WARNING"}
this memory limit.

.. 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 the boot sequence, you will observe 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
You can also examine the PKCS#11 slot created by OP-TEE to verify the
presence of the RSA-2048 key 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 survive across
reboots. As a consequence of this, because the root file system

Check warning on line 468 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": 468, "column": 13}}}, "severity": "INFO"}
was encrypted, the system will encounter a failure in mounting the
root file system during the subsequent boot.


If you were to reboot the system under the described circumstances, you
should expect to encounter the following error:

.. 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 aa0289b

Please sign in to comment.