<para>This option has no effect if the partition already exists.</para>
+ <para>This option may be combined with <varname>Verity=data</varname> in order to place the
+ encrypted partition inside a dm-verity protection envelope, see the description of
+ <varname>Verity=</varname> below.</para>
+
<xi:include href="version-info.xml" xpointer="v247"/></listitem>
</varlistentry>
<para>This option has no effect if the partition already exists.</para>
- <para>Usage of this option in combination with <varname>Encrypt=</varname> is not supported.</para>
+ <para><literal>data</literal> may be combined with <varname>Encrypt=</varname>, in which case the
+ partition is first encrypted with LUKS2 and the verity hash data is then generated from the
+ resulting ciphertext, i.e. Verity is the outer protection envelope and LUKS2 the inner. Tools such
+ as <citerefentry><refentrytitle>systemd-dissect</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ will then set up the dm-verity device first, and open the LUKS2 volume on top of it, so that all
+ encrypted data read is also authenticated via the verity root hash. Note that in this case the
+ verity hashes necessarily cover freshly generated ciphertext, hence the root hash (and thus the
+ default partition UUIDs derived from it) will change on every build, even if the plaintext contents
+ are fully reproducible. <varname>Encrypt=</varname> may not be combined with
+ <literal>Verity=hash</literal> or <literal>Verity=signature</literal>. Since the ciphertext is only
+ generated while the final image is built, <varname>Minimize=</varname> cannot be used for the hash
+ partition of an encrypted data partition; use <varname>SizeMaxBytes=</varname> on the data partition
+ to size the hash partition instead.</para>
<para>For each unique <varname>VerityMatchKey=</varname> value, a single verity data partition
(<literal>Verity=data</literal>) and a single verity hash partition (<literal>Verity=hash</literal>)
verity_mode_to_string(p->verity));
}
- if (p->verity != VERITY_OFF && p->encrypt != ENCRYPT_OFF)
+ if (IN_SET(p->verity, VERITY_HASH, VERITY_SIG) && p->encrypt != ENCRYPT_OFF)
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
- "Encrypting verity hash/data partitions is not supported.");
+ "Encrypting verity hash/signature partitions is not supported.");
if (p->verity == VERITY_SIG && (p->size_min != UINT64_MAX || p->size_max != UINT64_MAX))
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
if (dp->minimize == MINIMIZE_OFF && !(dp->copy_blocks_path || dp->copy_blocks_auto))
return log_syntax(NULL, LOG_ERR, p->definition_path, 1, SYNTHETIC_ERRNO(EINVAL),
"Minimize= set for verity hash partition but data partition does not set CopyBlocks= or Minimize=.");
+
+ /* The verity hash of an encrypted data partition covers the ciphertext, which is generated
+ * with a fresh volume key only when the final image is built, hence it cannot be
+ * precalculated for minimizing purposes. */
+ if (dp->encrypt != ENCRYPT_OFF)
+ return log_syntax(NULL, LOG_ERR, p->definition_path, 1, SYNTHETIC_ERRNO(EINVAL),
+ "Minimize= cannot be set for verity hash partitions whose data partition is encrypted, use SizeMaxBytes= on the data partition instead.");
}
LIST_FOREACH(partitions, p, context->partitions) {
return 0;
}
+static void partition_target_drop_decrypted(PartitionTarget *t) {
+ assert(t);
+
+ /* Deactivate the dm-crypt device again, so that subsequent access to the target reaches the
+ * encrypted data as it is stored on disk (i.e. the ciphertext). Requires the target to have been
+ * sync'ed first. */
+ t->decrypted = decrypted_partition_target_free(t->decrypted);
+}
+
static int partition_target_grow(PartitionTarget *t, uint64_t size) {
int r;
p->partno, FORMAT_TIMESPAN(time_spent, 0));
if (p->siblings[VERITY_HASH] && !partition_defer(context, p->siblings[VERITY_HASH])) {
+ /* The verity hash must cover the partition contents as stored on disk, i.e. the
+ * ciphertext if the partition is encrypted, hence tear down the dm-crypt device
+ * first. */
+ partition_target_drop_decrypted(t);
+
r = partition_format_verity_hash(context, p->siblings[VERITY_HASH],
/* node= */ NULL, partition_target_path(t));
if (r < 0)
return r;
if (p->siblings[VERITY_HASH] && !partition_defer(context, p->siblings[VERITY_HASH])) {
+ /* The verity hash must cover the partition contents as stored on disk, i.e. the
+ * ciphertext if the partition is encrypted, hence tear down the dm-crypt device
+ * first. */
+ partition_target_drop_decrypted(t);
+
r = partition_format_verity_hash(context, p->siblings[VERITY_HASH],
/* node= */ NULL, partition_target_path(t));
if (r < 0)