Blame SOURCES/0010-Add-support-for-creating-and-activating-integrity-de.patch

940a02
From 37f1aff5f5f967d6a4440d176f3de877aab789ac Mon Sep 17 00:00:00 2001
940a02
From: Vojtech Trefny <vtrefny@redhat.com>
940a02
Date: Mon, 20 Sep 2021 16:38:16 +0200
940a02
Subject: [PATCH 1/3] Add support for creating and activating integrity devices
940a02
940a02
This adds support for create, open and close actions for standalone
940a02
integrity devices using cryptsetup.
940a02
---
940a02
 configure.ac                        |   4 +-
940a02
 src/lib/plugin_apis/crypto.api      | 157 +++++++++++++++++
940a02
 src/plugins/crypto.c                | 261 +++++++++++++++++++++++++++-
940a02
 src/plugins/crypto.h                |  41 +++++
940a02
 src/python/gi/overrides/BlockDev.py |  24 +++
940a02
 tests/crypto_test.py                |  97 ++++++++++-
940a02
 6 files changed, 576 insertions(+), 8 deletions(-)
940a02
940a02
diff --git a/configure.ac b/configure.ac
940a02
index abe1412..13830ae 100644
940a02
--- a/configure.ac
940a02
+++ b/configure.ac
940a02
@@ -210,7 +210,9 @@ AS_IF([test "x$with_crypto" != "xno"],
940a02
       AS_IF([$PKG_CONFIG --atleast-version=2.0.3 libcryptsetup],
940a02
             [AC_DEFINE([LIBCRYPTSETUP_2])], [])
940a02
       AS_IF([$PKG_CONFIG --atleast-version=2.3.0 libcryptsetup],
940a02
-            [AC_DEFINE([LIBCRYPTSETUP_BITLK])], [])
940a02
+            [AC_DEFINE([LIBCRYPTSETUP_23])], [])
940a02
+      AS_IF([$PKG_CONFIG --atleast-version=2.4.0 libcryptsetup],
940a02
+            [AC_DEFINE([LIBCRYPTSETUP_24])], [])
940a02
       AS_IF([test "x$with_escrow" != "xno"],
940a02
             [LIBBLOCKDEV_PKG_CHECK_MODULES([NSS], [nss >= 3.18.0])
940a02
              LIBBLOCKDEV_CHECK_HEADER([volume_key/libvolume_key.h], [$GLIB_CFLAGS $NSS_CFLAGS], [libvolume_key.h not available])],
940a02
diff --git a/src/lib/plugin_apis/crypto.api b/src/lib/plugin_apis/crypto.api
940a02
index ef0217f..40e32c8 100644
940a02
--- a/src/lib/plugin_apis/crypto.api
940a02
+++ b/src/lib/plugin_apis/crypto.api
940a02
@@ -1,5 +1,6 @@
940a02
 #include <glib.h>
940a02
 #include <blockdev/utils.h>
940a02
+#include <libcryptsetup.h>
940a02
 
940a02
 #define BD_CRYPTO_LUKS_METADATA_SIZE G_GUINT64_CONSTANT (2097152ULL) // 2 MiB
940a02
 
940a02
@@ -245,6 +246,115 @@ GType bd_crypto_luks_extra_get_type () {
940a02
     return type;
940a02
 }
940a02
 
940a02
+#define BD_CRYPTO_TYPE_INTEGRITY_EXTRA (bd_crypto_integrity_extra_get_type ())
940a02
+GType bd_crypto_integrity_extra_get_type();
940a02
+
940a02
+/**
940a02
+ * BDCryptoIntegrityExtra:
940a02
+ * @sector_size: integrity sector size
940a02
+ * @journal_size: size of journal in bytes
940a02
+ * @journal_watermark: journal flush watermark in percents; in bitmap mode sectors-per-bit
940a02
+ * @journal_commit_time: journal commit time (or bitmap flush time) in ms
940a02
+ * @interleave_sectors: number of interleave sectors (power of two)
940a02
+ * @tag_size: tag size per-sector in bytes
940a02
+ * @buffer_sectors: number of sectors in one buffer
940a02
+ */
940a02
+typedef struct BDCryptoIntegrityExtra {
940a02
+    guint32 sector_size;
940a02
+    guint64 journal_size;
940a02
+    guint journal_watermark;
940a02
+    guint journal_commit_time;
940a02
+    guint32 interleave_sectors;
940a02
+    guint32 tag_size;
940a02
+    guint32 buffer_sectors;
940a02
+} BDCryptoIntegrityExtra;
940a02
+
940a02
+/**
940a02
+ * bd_crypto_integrity_extra_copy: (skip)
940a02
+ * @extra: (allow-none): %BDCryptoIntegrityExtra to copy
940a02
+ *
940a02
+ * Creates a new copy of @extra.
940a02
+ */
940a02
+BDCryptoIntegrityExtra* bd_crypto_integrity_extra_copy (BDCryptoIntegrityExtra *extra) {
940a02
+    if (extra == NULL)
940a02
+        return NULL;
940a02
+
940a02
+    BDCryptoIntegrityExtra *new_extra = g_new0 (BDCryptoIntegrityExtra, 1);
940a02
+
940a02
+    new_extra->sector_size = extra->sector_size;
940a02
+    new_extra->journal_size = extra->journal_size;
940a02
+    new_extra->journal_watermark = extra->journal_watermark;
940a02
+    new_extra->journal_commit_time = extra->journal_commit_time;
940a02
+    new_extra->interleave_sectors = extra->interleave_sectors;
940a02
+    new_extra->tag_size = extra->tag_size;
940a02
+    new_extra->buffer_sectors = extra->buffer_sectors;
940a02
+
940a02
+    return new_extra;
940a02
+}
940a02
+
940a02
+/**
940a02
+ * bd_crypto_integrity_extra_free: (skip)
940a02
+ * @extra: (allow-none): %BDCryptoIntegrityExtra to free
940a02
+ *
940a02
+ * Frees @extra.
940a02
+ */
940a02
+void bd_crypto_integrity_extra_free (BDCryptoIntegrityExtra *extra) {
940a02
+    if (extra == NULL)
940a02
+        return;
940a02
+
940a02
+    g_free (extra);
940a02
+}
940a02
+
940a02
+/**
940a02
+ * bd_crypto_integrity_extra_new: (constructor)
940a02
+ * @sector_size: integrity sector size, 0 for default (512)
940a02
+ * @journal_size: size of journal in bytes
940a02
+ * @journal_watermark: journal flush watermark in percents; in bitmap mode sectors-per-bit
940a02
+ * @journal_commit_time: journal commit time (or bitmap flush time) in ms
940a02
+ * @interleave_sectors: number of interleave sectors (power of two)
940a02
+ * @tag_size: tag size per-sector in bytes
940a02
+ * @buffer_sectors: number of sectors in one buffer
940a02
+ *
940a02
+ * Returns: (transfer full): a new Integrity extra argument
940a02
+ */
940a02
+BDCryptoIntegrityExtra* bd_crypto_integrity_extra_new (guint64 sector_size, guint64 journal_size, guint journal_watermark, guint journal_commit_time, guint64 interleave_sectors, guint64 tag_size, guint64 buffer_sectors) {
940a02
+    BDCryptoIntegrityExtra *ret = g_new0 (BDCryptoIntegrityExtra, 1);
940a02
+    ret->sector_size = sector_size;
940a02
+    ret->journal_size = journal_size;
940a02
+    ret->journal_watermark = journal_watermark;
940a02
+    ret->journal_commit_time = journal_commit_time;
940a02
+    ret->interleave_sectors = interleave_sectors;
940a02
+    ret->tag_size = tag_size;
940a02
+    ret->buffer_sectors = buffer_sectors;
940a02
+
940a02
+    return ret;
940a02
+}
940a02
+
940a02
+GType bd_crypto_integrity_extra_get_type () {
940a02
+    static GType type = 0;
940a02
+
940a02
+    if (G_UNLIKELY(type == 0)) {
940a02
+        type = g_boxed_type_register_static("BDCryptoIntegrityExtra",
940a02
+                                            (GBoxedCopyFunc) bd_crypto_integrity_extra_copy,
940a02
+                                            (GBoxedFreeFunc) bd_crypto_integrity_extra_free);
940a02
+    }
940a02
+
940a02
+    return type;
940a02
+}
940a02
+
940a02
+typedef enum {
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL         = CRYPT_ACTIVATE_NO_JOURNAL,
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_RECOVERY           = CRYPT_ACTIVATE_RECOVERY,
940a02
+#ifdef CRYPT_ACTIVATE_NO_JOURNAL_BITMAP
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL_BITMAP  = CRYPT_ACTIVATE_NO_JOURNAL_BITMAP,
940a02
+#endif
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE        = CRYPT_ACTIVATE_RECALCULATE,
940a02
+#ifdef CRYPT_ACTIVATE_RECALCULATE_RESET
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE_RESET  = CRYPT_ACTIVATE_RECALCULATE_RESET,
940a02
+#endif
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_ALLOW_DISCARDS     = CRYPT_ACTIVATE_ALLOW_DISCARDS,
940a02
+} BDCryptoIntegrityOpenFlags;
940a02
+
940a02
 #define BD_CRYPTO_TYPE_LUKS_INFO (bd_crypto_luks_info_get_type ())
940a02
 GType bd_crypto_luks_info_get_type();
940a02
 
940a02
@@ -857,6 +967,53 @@ BDCryptoLUKSInfo* bd_crypto_luks_info (const gchar *luks_device, GError **error)
940a02
  */
940a02
 BDCryptoIntegrityInfo* bd_crypto_integrity_info (const gchar *device, GError **error);
940a02
 
940a02
+/**
940a02
+ * bd_crypto_integrity_format:
940a02
+ * @device: a device to format as integrity
940a02
+ * @algorithm: integrity algorithm specification (e.g. "crc32c" or "sha256") or %NULL to use the default
940a02
+ * @wipe: whether to wipe the device after format; a device that is not initially wiped will contain invalid checksums
940a02
+ * @key_data: (allow-none) (array length=key_size): integrity key or %NULL if not needed
940a02
+ * @key_size: size the integrity key and @key_data
940a02
+ * @extra: (allow-none): extra arguments for integrity format creation
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Formats the given @device as integrity according to the other parameters given.
940a02
+ *
940a02
+ * Returns: whether the given @device was successfully formatted as integrity or not
940a02
+ * (the @error) contains the error in such cases)
940a02
+ *
940a02
+ * Tech category: %BD_CRYPTO_TECH_INTEGRITY-%BD_CRYPTO_TECH_MODE_CREATE
940a02
+ */
940a02
+gboolean bd_crypto_integrity_format (const gchar *device, const gchar *algorithm, gboolean wipe, const guint8* key_data, gsize key_size, BDCryptoIntegrityExtra *extra, GError **error);
940a02
+
940a02
+/**
940a02
+ * bd_crypto_integrity_open:
940a02
+ * @device: integrity device to open
940a02
+ * @name: name for the opened @device
940a02
+ * @algorithm: (allow-none): integrity algorithm specification (e.g. "crc32c" or "sha256") or %NULL to use the default
940a02
+ * @key_data: (allow-none) (array length=key_size): integrity key or %NULL if not needed
940a02
+ * @key_size: size the integrity key and @key_data
940a02
+ * @flags: flags for the integrity device activation
940a02
+ * @extra: (allow-none): extra arguments for integrity open
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: whether the @device was successfully opened or not
940a02
+ *
940a02
+ * Tech category: %BD_CRYPTO_TECH_INTEGRITY-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
940a02
+ */
940a02
+gboolean bd_crypto_integrity_open (const gchar *device, const gchar *name, const gchar *algorithm, const guint8* key_data, gsize key_size, BDCryptoIntegrityOpenFlags flags, BDCryptoIntegrityExtra *extra, GError **error);
940a02
+
940a02
+/**
940a02
+ * bd_crypto_integrity_close:
940a02
+ * @integrity_device: integrity device to close
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: whether the given @integrity_device was successfully closed or not
940a02
+ *
940a02
+ * Tech category: %BD_CRYPTO_TECH_INTEGRITY-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
940a02
+ */
940a02
+gboolean bd_crypto_integrity_close (const gchar *integrity_device, GError **error);
940a02
+
940a02
 /**
940a02
  * bd_crypto_device_seems_encrypted:
940a02
  * @device: the queried device
940a02
diff --git a/src/plugins/crypto.c b/src/plugins/crypto.c
940a02
index 4fad9a8..b1b0700 100644
940a02
--- a/src/plugins/crypto.c
940a02
+++ b/src/plugins/crypto.c
940a02
@@ -50,6 +50,18 @@
940a02
 
940a02
 #define SECTOR_SIZE 512
940a02
 
940a02
+#define DEFAULT_LUKS_KEYSIZE_BITS 256
940a02
+#define DEFAULT_LUKS_CIPHER "aes-xts-plain64"
940a02
+
940a02
+#ifdef LIBCRYPTSETUP_23
940a02
+/* 0 for autodetect since 2.3.0 */
940a02
+#define DEFAULT_INTEGRITY_TAG_SIZE 0
940a02
+#else
940a02
+/* we need some sane default for older versions, users should specify tag size when using
940a02
+   other algorithms than the default crc32c */
940a02
+#define DEFAULT_INTEGRITY_TAG_SIZE 4
940a02
+#endif
940a02
+
940a02
 #define UNUSED __attribute__((unused))
940a02
 
940a02
 /**
940a02
@@ -146,6 +158,43 @@ BDCryptoLUKSExtra* bd_crypto_luks_extra_new (guint64 data_alignment, const gchar
940a02
     return ret;
940a02
 }
940a02
 
940a02
+BDCryptoIntegrityExtra* bd_crypto_integrity_extra_new (guint64 sector_size, guint64 journal_size, guint journal_watermark, guint journal_commit_time, guint64 interleave_sectors, guint64 tag_size, guint64 buffer_sectors) {
940a02
+    BDCryptoIntegrityExtra *ret = g_new0 (BDCryptoIntegrityExtra, 1);
940a02
+    ret->sector_size = sector_size;
940a02
+    ret->journal_size = journal_size;
940a02
+    ret->journal_watermark = journal_watermark;
940a02
+    ret->journal_commit_time = journal_commit_time;
940a02
+    ret->interleave_sectors = interleave_sectors;
940a02
+    ret->tag_size = tag_size;
940a02
+    ret->buffer_sectors = buffer_sectors;
940a02
+
940a02
+    return ret;
940a02
+}
940a02
+
940a02
+BDCryptoIntegrityExtra* bd_crypto_integrity_extra_copy (BDCryptoIntegrityExtra *extra) {
940a02
+    if (extra == NULL)
940a02
+        return NULL;
940a02
+
940a02
+    BDCryptoIntegrityExtra *new_extra = g_new0 (BDCryptoIntegrityExtra, 1);
940a02
+
940a02
+    new_extra->sector_size = extra->sector_size;
940a02
+    new_extra->journal_size = extra->journal_size;
940a02
+    new_extra->journal_watermark = extra->journal_watermark;
940a02
+    new_extra->journal_commit_time = extra->journal_commit_time;
940a02
+    new_extra->interleave_sectors = extra->interleave_sectors;
940a02
+    new_extra->tag_size = extra->tag_size;
940a02
+    new_extra->buffer_sectors = extra->buffer_sectors;
940a02
+
940a02
+    return new_extra;
940a02
+}
940a02
+
940a02
+void bd_crypto_integrity_extra_free (BDCryptoIntegrityExtra *extra) {
940a02
+    if (extra == NULL)
940a02
+        return;
940a02
+
940a02
+    g_free (extra);
940a02
+}
940a02
+
940a02
 void bd_crypto_luks_info_free (BDCryptoLUKSInfo *info) {
940a02
     if (info == NULL)
940a02
         return;
940a02
@@ -346,15 +395,15 @@ gboolean bd_crypto_is_tech_avail (BDCryptoTech tech, guint64 mode, GError **erro
940a02
                          "Integrity technology requires libcryptsetup >= 2.0");
940a02
             return FALSE;
940a02
 #endif
940a02
-            ret = mode & (BD_CRYPTO_TECH_MODE_QUERY);
940a02
+            ret = mode & (BD_CRYPTO_TECH_MODE_CREATE|BD_CRYPTO_TECH_MODE_OPEN_CLOSE|BD_CRYPTO_TECH_MODE_QUERY);
940a02
             if (ret != mode) {
940a02
                 g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
940a02
-                             "Only 'query' supported for Integrity");
940a02
+                             "Only 'create', 'open' and 'query' supported for Integrity");
940a02
                 return FALSE;
940a02
             } else
940a02
                 return TRUE;
940a02
         case BD_CRYPTO_TECH_BITLK:
940a02
-#ifndef LIBCRYPTSETUP_BITLK
940a02
+#ifndef LIBCRYPTSETUP_23
940a02
             g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
940a02
                          "BITLK technology requires libcryptsetup >= 2.3.0");
940a02
             return FALSE;
940a02
@@ -2035,6 +2084,208 @@ BDCryptoIntegrityInfo* bd_crypto_integrity_info (const gchar *device, GError **e
940a02
 }
940a02
 #endif
940a02
 
940a02
+static int _wipe_progress (guint64 size, guint64 offset, void *usrptr) {
940a02
+    /* "convert" the progress from 0-100 to 50-100 because wipe starts at 50 in bd_crypto_integrity_format */
940a02
+    gdouble progress = 50 + (((gdouble) offset / size) * 100) / 2;
940a02
+    bd_utils_report_progress (*(guint64 *) usrptr, progress, "Integrity device wipe in progress");
940a02
+
940a02
+    return 0;
940a02
+}
940a02
+
940a02
+/**
940a02
+ * bd_crypto_integrity_format:
940a02
+ * @device: a device to format as integrity
940a02
+ * @algorithm: integrity algorithm specification (e.g. "crc32c" or "sha256")
940a02
+ * @wipe: whether to wipe the device after format; a device that is not initially wiped will contain invalid checksums
940a02
+ * @key_data: (allow-none) (array length=key_size): integrity key or %NULL if not needed
940a02
+ * @key_size: size the integrity key and @key_data
940a02
+ * @extra: (allow-none): extra arguments for integrity format creation
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Formats the given @device as integrity according to the other parameters given.
940a02
+ *
940a02
+ * Returns: whether the given @device was successfully formatted as integrity or not
940a02
+ * (the @error) contains the error in such cases)
940a02
+ *
940a02
+ * Tech category: %BD_CRYPTO_TECH_INTEGRITY-%BD_CRYPTO_TECH_MODE_CREATE
940a02
+ */
940a02
+gboolean bd_crypto_integrity_format (const gchar *device, const gchar *algorithm, gboolean wipe, const guint8* key_data, gsize key_size, BDCryptoIntegrityExtra *extra, GError **error) {
940a02
+    struct crypt_device *cd = NULL;
940a02
+    gint ret;
940a02
+    guint64 progress_id = 0;
940a02
+    gchar *msg = NULL;
940a02
+    struct crypt_params_integrity params = ZERO_INIT;
940a02
+    g_autofree gchar *tmp_name = NULL;
940a02
+    g_autofree gchar *tmp_path = NULL;
940a02
+    g_autofree gchar *dev_name = NULL;
940a02
+
940a02
+    msg = g_strdup_printf ("Started formatting '%s' as integrity device", device);
940a02
+    progress_id = bd_utils_report_started (msg);
940a02
+    g_free (msg);
940a02
+
940a02
+    ret = crypt_init (&cd, device);
940a02
+    if (ret != 0) {
940a02
+        g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
940a02
+                     "Failed to initialize device: %s", strerror_l (-ret, c_locale));
940a02
+        bd_utils_report_finished (progress_id, (*error)->message);
940a02
+        return FALSE;
940a02
+    }
940a02
+
940a02
+    if (extra) {
940a02
+        params.sector_size = extra->sector_size;
940a02
+        params.journal_size = extra->journal_size;
940a02
+        params.journal_watermark = extra->journal_watermark;
940a02
+        params.journal_commit_time = extra->journal_commit_time;
940a02
+        params.interleave_sectors = extra->interleave_sectors;
940a02
+        params.tag_size = extra->tag_size;
940a02
+        params.buffer_sectors = extra->buffer_sectors;
940a02
+    }
940a02
+
940a02
+    params.integrity_key_size = key_size;
940a02
+    params.integrity = algorithm;
940a02
+    params.tag_size = params.tag_size ? params.tag_size : DEFAULT_INTEGRITY_TAG_SIZE;
940a02
+
940a02
+    ret = crypt_format (cd, CRYPT_INTEGRITY, NULL, NULL, NULL, NULL, 0, &params);
940a02
+    if (ret != 0) {
940a02
+        g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_FORMAT_FAILED,
940a02
+                     "Failed to format device: %s", strerror_l (-ret, c_locale));
940a02
+        crypt_free (cd);
940a02
+        bd_utils_report_finished (progress_id, (*error)->message);
940a02
+        return FALSE;
940a02
+    }
940a02
+
940a02
+    if (wipe) {
940a02
+        bd_utils_report_progress (progress_id, 50, "Format created");
940a02
+
940a02
+        dev_name = g_path_get_basename (device);
940a02
+        tmp_name = g_strdup_printf ("bd-temp-integrity-%s-%d", dev_name, g_random_int ());
940a02
+        tmp_path = g_strdup_printf ("%s/%s", crypt_get_dir (), tmp_name);
940a02
+
940a02
+        ret = crypt_activate_by_volume_key (cd, tmp_name, (const char *) key_data, key_size,
940a02
+                                            CRYPT_ACTIVATE_PRIVATE | CRYPT_ACTIVATE_NO_JOURNAL);
940a02
+        if (ret != 0) {
940a02
+            g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
940a02
+                         "Failed to activate the newly created integrity device for wiping: %s",
940a02
+                         strerror_l (-ret, c_locale));
940a02
+            crypt_free (cd);
940a02
+            bd_utils_report_finished (progress_id, (*error)->message);
940a02
+            return FALSE;
940a02
+        }
940a02
+
940a02
+        bd_utils_report_progress (progress_id, 50, "Starting to wipe the newly created integrity device");
940a02
+        ret = crypt_wipe (cd, tmp_path, CRYPT_WIPE_ZERO, 0, 0, 1048576,
940a02
+                          0, &_wipe_progress, &progress_id);
940a02
+        bd_utils_report_progress (progress_id, 100, "Wipe finished");
940a02
+        if (ret != 0) {
940a02
+            g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
940a02
+                         "Failed to wipe the newly created integrity device: %s",
940a02
+                         strerror_l (-ret, c_locale));
940a02
+
940a02
+            ret = crypt_deactivate (cd, tmp_name);
940a02
+            if (ret != 0)
940a02
+                g_warning ("Failed to deactivate temporary device %s", tmp_name);
940a02
+
940a02
+            crypt_free (cd);
940a02
+            bd_utils_report_finished (progress_id, (*error)->message);
940a02
+            return FALSE;
940a02
+        }
940a02
+
940a02
+        ret = crypt_deactivate (cd, tmp_name);
940a02
+        if (ret != 0)
940a02
+            g_warning ("Failed to deactivate temporary device %s", tmp_name);
940a02
+
940a02
+    } else
940a02
+        bd_utils_report_finished (progress_id, "Completed");
940a02
+
940a02
+    crypt_free (cd);
940a02
+
940a02
+    return TRUE;
940a02
+}
940a02
+
940a02
+/**
940a02
+ * bd_crypto_integrity_open:
940a02
+ * @device: integrity device to open
940a02
+ * @name: name for the opened @device
940a02
+ * @algorithm: (allow-none): integrity algorithm specification (e.g. "crc32c" or "sha256") or %NULL to use the default
940a02
+ * @key_data: (allow-none) (array length=key_size): integrity key or %NULL if not needed
940a02
+ * @key_size: size the integrity key and @key_data
940a02
+ * @flags: flags for the integrity device activation
940a02
+ * @extra: (allow-none): extra arguments for integrity open
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: whether the @device was successfully opened or not
940a02
+ *
940a02
+ * Tech category: %BD_CRYPTO_TECH_INTEGRITY-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
940a02
+ */
940a02
+gboolean bd_crypto_integrity_open (const gchar *device, const gchar *name, const gchar *algorithm, const guint8* key_data, gsize key_size, BDCryptoIntegrityOpenFlags flags, BDCryptoIntegrityExtra *extra, GError **error) {
940a02
+    struct crypt_device *cd = NULL;
940a02
+    gint ret = 0;
940a02
+    guint64 progress_id = 0;
940a02
+    gchar *msg = NULL;
940a02
+    struct crypt_params_integrity params = ZERO_INIT;
940a02
+
940a02
+    params.integrity = algorithm;
940a02
+    params.integrity_key_size = key_size;
940a02
+
940a02
+    if (extra) {
940a02
+        params.sector_size = extra->sector_size;
940a02
+        params.journal_size = extra->journal_size;
940a02
+        params.journal_watermark = extra->journal_watermark;
940a02
+        params.journal_commit_time = extra->journal_commit_time;
940a02
+        params.interleave_sectors = extra->interleave_sectors;
940a02
+        params.tag_size = extra->tag_size;
940a02
+        params.buffer_sectors = extra->buffer_sectors;
940a02
+    }
940a02
+
940a02
+    msg = g_strdup_printf ("Started opening '%s' integrity device", device);
940a02
+    progress_id = bd_utils_report_started (msg);
940a02
+    g_free (msg);
940a02
+
940a02
+    ret = crypt_init (&cd, device);
940a02
+    if (ret != 0) {
940a02
+        g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
940a02
+                     "Failed to initialize device: %s", strerror_l (-ret, c_locale));
940a02
+        bd_utils_report_finished (progress_id, (*error)->message);
940a02
+        return FALSE;
940a02
+    }
940a02
+
940a02
+    ret = crypt_load (cd, CRYPT_INTEGRITY, &params);
940a02
+    if (ret != 0) {
940a02
+        g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
940a02
+                     "Failed to load device's parameters: %s", strerror_l (-ret, c_locale));
940a02
+        crypt_free (cd);
940a02
+        bd_utils_report_finished (progress_id, (*error)->message);
940a02
+        return FALSE;
940a02
+    }
940a02
+
940a02
+    ret = crypt_activate_by_volume_key (cd, name, (const char *) key_data, key_size, flags);
940a02
+    if (ret < 0) {
940a02
+        g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
940a02
+                     "Failed to activate device: %s", strerror_l (-ret, c_locale));
940a02
+
940a02
+        crypt_free (cd);
940a02
+        bd_utils_report_finished (progress_id, (*error)->message);
940a02
+        return FALSE;
940a02
+    }
940a02
+
940a02
+    crypt_free (cd);
940a02
+    bd_utils_report_finished (progress_id, "Completed");
940a02
+    return TRUE;
940a02
+}
940a02
+
940a02
+/**
940a02
+ * bd_crypto_integrity_close:
940a02
+ * @integrity_device: integrity device to close
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: whether the given @integrity_device was successfully closed or not
940a02
+ *
940a02
+ * Tech category: %BD_CRYPTO_TECH_INTEGRITY-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
940a02
+ */
940a02
+gboolean bd_crypto_integrity_close (const gchar *integrity_device, GError **error) {
940a02
+    return _crypto_close (integrity_device, "integrity", error);
940a02
+}
940a02
+
940a02
 /**
940a02
  * bd_crypto_device_seems_encrypted:
940a02
  * @device: the queried device
940a02
@@ -2472,7 +2723,7 @@ gboolean bd_crypto_escrow_device (const gchar *device, const gchar *passphrase,
940a02
  *
940a02
  * Tech category: %BD_CRYPTO_TECH_BITLK-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
940a02
  */
940a02
-#ifndef LIBCRYPTSETUP_BITLK
940a02
+#ifndef LIBCRYPTSETUP_23
940a02
 gboolean bd_crypto_bitlk_open (const gchar *device UNUSED, const gchar *name UNUSED, const guint8* pass_data UNUSED, gsize data_len UNUSED, gboolean read_only UNUSED, GError **error) {
940a02
     /* this will return FALSE and set error, because BITLK technology is not available */
940a02
     return bd_crypto_is_tech_avail (BD_CRYPTO_TECH_BITLK, BD_CRYPTO_TECH_MODE_OPEN_CLOSE, error);
940a02
@@ -2542,7 +2793,7 @@ gboolean bd_crypto_bitlk_open (const gchar *device, const gchar *name, const gui
940a02
  *
940a02
  * Tech category: %BD_CRYPTO_TECH_BITLK-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
940a02
  */
940a02
-#ifndef LIBCRYPTSETUP_BITLK
940a02
+#ifndef LIBCRYPTSETUP_23
940a02
 gboolean bd_crypto_bitlk_close (const gchar *bitlk_device UNUSED, GError **error) {
940a02
     /* this will return FALSE and set error, because BITLK technology is not available */
940a02
     return bd_crypto_is_tech_avail (BD_CRYPTO_TECH_BITLK, BD_CRYPTO_TECH_MODE_OPEN_CLOSE, error);
940a02
diff --git a/src/plugins/crypto.h b/src/plugins/crypto.h
940a02
index a38724d..166e558 100644
940a02
--- a/src/plugins/crypto.h
940a02
+++ b/src/plugins/crypto.h
940a02
@@ -116,6 +116,43 @@ void bd_crypto_luks_extra_free (BDCryptoLUKSExtra *extra);
940a02
 BDCryptoLUKSExtra* bd_crypto_luks_extra_copy (BDCryptoLUKSExtra *extra);
940a02
 BDCryptoLUKSExtra* bd_crypto_luks_extra_new (guint64 data_alignment, const gchar *data_device, const gchar *integrity, guint64 sector_size, const gchar *label, const gchar *subsystem, BDCryptoLUKSPBKDF *pbkdf);
940a02
 
940a02
+/**
940a02
+ * BDCryptoIntegrityExtra:
940a02
+ * @sector_size: integrity sector size
940a02
+ * @journal_size: size of journal in bytes
940a02
+ * @journal_watermark: journal flush watermark in percents; in bitmap mode sectors-per-bit
940a02
+ * @journal_commit_time: journal commit time (or bitmap flush time) in ms
940a02
+ * @interleave_sectors: number of interleave sectors (power of two)
940a02
+ * @tag_size: tag size per-sector in bytes
940a02
+ * @buffer_sectors: number of sectors in one buffer
940a02
+ */
940a02
+typedef struct BDCryptoIntegrityExtra {
940a02
+    guint32 sector_size;
940a02
+    guint64 journal_size;
940a02
+    guint journal_watermark;
940a02
+    guint journal_commit_time;
940a02
+    guint32 interleave_sectors;
940a02
+    guint32 tag_size;
940a02
+    guint32 buffer_sectors;
940a02
+} BDCryptoIntegrityExtra;
940a02
+
940a02
+void bd_crypto_integrity_extra_free (BDCryptoIntegrityExtra *extra);
940a02
+BDCryptoIntegrityExtra* bd_crypto_integrity_extra_copy (BDCryptoIntegrityExtra *extra);
940a02
+BDCryptoIntegrityExtra* bd_crypto_integrity_extra_new (guint64 sector_size, guint64 journal_size, guint journal_watermark, guint journal_commit_time, guint64 interleave_sectors, guint64 tag_size, guint64 buffer_sectors);
940a02
+
940a02
+typedef enum {
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL         = CRYPT_ACTIVATE_NO_JOURNAL,
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_RECOVERY           = CRYPT_ACTIVATE_RECOVERY,
940a02
+#ifdef CRYPT_ACTIVATE_NO_JOURNAL_BITMAP
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL_BITMAP  = CRYPT_ACTIVATE_NO_JOURNAL_BITMAP,
940a02
+#endif
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE        = CRYPT_ACTIVATE_RECALCULATE,
940a02
+#ifdef CRYPT_ACTIVATE_RECALCULATE_RESET
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE_RESET  = CRYPT_ACTIVATE_RECALCULATE_RESET,
940a02
+#endif
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_ALLOW_DISCARDS     = CRYPT_ACTIVATE_ALLOW_DISCARDS,
940a02
+} BDCryptoIntegrityOpenFlags;
940a02
+
940a02
 /**
940a02
  * BDCryptoLUKSInfo:
940a02
  * @version: LUKS version
940a02
@@ -209,6 +246,10 @@ gboolean bd_crypto_luks_header_restore (const gchar *device, const gchar *backup
940a02
 BDCryptoLUKSInfo* bd_crypto_luks_info (const gchar *luks_device, GError **error);
940a02
 BDCryptoIntegrityInfo* bd_crypto_integrity_info (const gchar *device, GError **error);
940a02
 
940a02
+gboolean bd_crypto_integrity_format (const gchar *device, const gchar *algorithm, gboolean wipe, const guint8* key_data, gsize key_size, BDCryptoIntegrityExtra *extra, GError **error);
940a02
+gboolean bd_crypto_integrity_open (const gchar *device, const gchar *name, const gchar *algorithm, const guint8* key_data, gsize key_size, BDCryptoIntegrityOpenFlags flags, BDCryptoIntegrityExtra *extra, GError **error);
940a02
+gboolean bd_crypto_integrity_close (const gchar *integrity_device, GError **error);
940a02
+
940a02
 gboolean bd_crypto_device_seems_encrypted (const gchar *device, GError **error);
940a02
 gboolean bd_crypto_tc_open (const gchar *device, const gchar *name, const guint8* pass_data, gsize data_len, gboolean read_only, GError **error);
940a02
 gboolean bd_crypto_tc_open_full (const gchar *device, const gchar *name, const guint8* pass_data, gsize data_len, const gchar **keyfiles, gboolean hidden, gboolean system, gboolean veracrypt, guint32 veracrypt_pim, gboolean read_only, GError **error);
940a02
diff --git a/src/python/gi/overrides/BlockDev.py b/src/python/gi/overrides/BlockDev.py
940a02
index 715a262..71bcd31 100644
940a02
--- a/src/python/gi/overrides/BlockDev.py
940a02
+++ b/src/python/gi/overrides/BlockDev.py
940a02
@@ -276,6 +276,30 @@ def crypto_bitlk_open(device, name, passphrase, read_only=False):
940a02
 __all__.append("crypto_bitlk_open")
940a02
 
940a02
 
940a02
+class CryptoIntegrityExtra(BlockDev.CryptoIntegrityExtra):
940a02
+    def __new__(cls, sector_size=0, journal_size=0, journal_watermark=0, journal_commit_time=0, interleave_sectors=0, tag_size=0, buffer_sectors=0):
940a02
+        ret = BlockDev.CryptoIntegrityExtra.new(sector_size, journal_size, journal_watermark, journal_commit_time, interleave_sectors, tag_size, buffer_sectors)
940a02
+        ret.__class__ = cls
940a02
+        return ret
940a02
+    def __init__(self, *args, **kwargs):   # pylint: disable=unused-argument
940a02
+        super(CryptoIntegrityExtra, self).__init__()  #pylint: disable=bad-super-call
940a02
+CryptoIntegrityExtra = override(CryptoIntegrityExtra)
940a02
+__all__.append("CryptoIntegrityExtra")
940a02
+
940a02
+
940a02
+_crypto_integrity_format = BlockDev.crypto_integrity_format
940a02
+@override(BlockDev.crypto_integrity_format)
940a02
+def crypto_integrity_format(device, algorithm=None, wipe=True, key_data=None, extra=None):
940a02
+    return _crypto_integrity_format(device, algorithm, wipe, key_data, extra)
940a02
+__all__.append("crypto_integrity_format")
940a02
+
940a02
+_crypto_integrity_open = BlockDev.crypto_integrity_open
940a02
+@override(BlockDev.crypto_integrity_open)
940a02
+def crypto_integrity_open(device, name, algorithm, key_data=None, flags=0, extra=None):
940a02
+    return _crypto_integrity_open(device, name, algorithm, key_data, flags, extra)
940a02
+__all__.append("crypto_integrity_open")
940a02
+
940a02
+
940a02
 _dm_create_linear = BlockDev.dm_create_linear
940a02
 @override(BlockDev.dm_create_linear)
940a02
 def dm_create_linear(map_name, device, length, uuid=None):
940a02
diff --git a/tests/crypto_test.py b/tests/crypto_test.py
940a02
index 0aecc03..1c6832e 100644
940a02
--- a/tests/crypto_test.py
940a02
+++ b/tests/crypto_test.py
940a02
@@ -2,6 +2,7 @@ import unittest
940a02
 import os
940a02
 import tempfile
940a02
 import overrides_hack
940a02
+import secrets
940a02
 import shutil
940a02
 import subprocess
940a02
 import six
940a02
@@ -42,6 +43,8 @@ class CryptoTestCase(unittest.TestCase):
940a02
 
940a02
     requested_plugins = BlockDev.plugin_specs_from_names(("crypto", "loop"))
940a02
 
940a02
+    _dm_name = "libblockdevTestLUKS"
940a02
+
940a02
     @classmethod
940a02
     def setUpClass(cls):
940a02
         unittest.TestCase.setUpClass()
940a02
@@ -72,7 +75,7 @@ class CryptoTestCase(unittest.TestCase):
940a02
 
940a02
     def _clean_up(self):
940a02
         try:
940a02
-            BlockDev.crypto_luks_close("libblockdevTestLUKS")
940a02
+            BlockDev.crypto_luks_close(self._dm_name)
940a02
         except:
940a02
             pass
940a02
 
940a02
@@ -964,7 +967,8 @@ class CryptoTestInfo(CryptoTestCase):
940a02
         succ = BlockDev.crypto_luks_close("libblockdevTestLUKS")
940a02
         self.assertTrue(succ)
940a02
 
940a02
-class CryptoTestIntegrity(CryptoTestCase):
940a02
+
940a02
+class CryptoTestLUKS2Integrity(CryptoTestCase):
940a02
     @tag_test(TestTags.SLOW)
940a02
     @unittest.skipUnless(HAVE_LUKS2, "LUKS 2 not supported")
940a02
     def test_luks2_integrity(self):
940a02
@@ -1151,3 +1155,92 @@ class CryptoTestBitlk(CryptoTestCase):
940a02
         succ = BlockDev.crypto_bitlk_close("libblockdevTestBitlk")
940a02
         self.assertTrue(succ)
940a02
         self.assertFalse(os.path.exists("/dev/mapper/libblockdevTestBitlk"))
940a02
+
940a02
+
940a02
+class CryptoTestIntegrity(CryptoTestCase):
940a02
+
940a02
+    _dm_name = "libblockdevTestIntegrity"
940a02
+
940a02
+    @unittest.skipUnless(HAVE_LUKS2, "Integrity not supported")
940a02
+    def test_integrity(self):
940a02
+        # basic format+open+close test
940a02
+        succ = BlockDev.crypto_integrity_format(self.loop_dev, "sha256", False)
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        succ = BlockDev.crypto_integrity_open(self.loop_dev, self._dm_name, "sha256")
940a02
+        self.assertTrue(succ)
940a02
+        self.assertTrue(os.path.exists("/dev/mapper/%s" % self._dm_name))
940a02
+
940a02
+        info = BlockDev.crypto_integrity_info(self._dm_name)
940a02
+        self.assertEqual(info.algorithm, "sha256")
940a02
+
940a02
+        succ = BlockDev.crypto_integrity_close(self._dm_name)
940a02
+        self.assertTrue(succ)
940a02
+        self.assertFalse(os.path.exists("/dev/mapper/%s" % self._dm_name))
940a02
+
940a02
+        # same now with a keyed algorithm
940a02
+        key = list(secrets.token_bytes(64))
940a02
+
940a02
+        succ = BlockDev.crypto_integrity_format(self.loop_dev, "hmac(sha256)", False, key)
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        succ = BlockDev.crypto_integrity_open(self.loop_dev, self._dm_name, "hmac(sha256)", key)
940a02
+        self.assertTrue(succ)
940a02
+        self.assertTrue(os.path.exists("/dev/mapper/%s" % self._dm_name))
940a02
+
940a02
+        info = BlockDev.crypto_integrity_info(self._dm_name)
940a02
+        self.assertEqual(info.algorithm, "hmac(sha256)")
940a02
+
940a02
+        succ = BlockDev.crypto_integrity_close(self._dm_name)
940a02
+        self.assertTrue(succ)
940a02
+        self.assertFalse(os.path.exists("/dev/mapper/%s" % self._dm_name))
940a02
+
940a02
+        # same with some custom parameters
940a02
+        extra = BlockDev.CryptoIntegrityExtra(sector_size=4096, interleave_sectors=65536)
940a02
+        succ = BlockDev.crypto_integrity_format(self.loop_dev, "crc32c", wipe=False, extra=extra)
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        succ = BlockDev.crypto_integrity_open(self.loop_dev, self._dm_name, "crc32c")
940a02
+        self.assertTrue(succ)
940a02
+        self.assertTrue(os.path.exists("/dev/mapper/%s" % self._dm_name))
940a02
+
940a02
+        info = BlockDev.crypto_integrity_info(self._dm_name)
940a02
+        self.assertEqual(info.algorithm, "crc32c")
940a02
+        self.assertEqual(info.sector_size, 4096)
940a02
+        self.assertEqual(info.interleave_sectors, 65536)
940a02
+
940a02
+        succ = BlockDev.crypto_integrity_close(self._dm_name)
940a02
+        self.assertTrue(succ)
940a02
+        self.assertFalse(os.path.exists("/dev/mapper/%s" % self._dm_name))
940a02
+
940a02
+    @tag_test(TestTags.SLOW)
940a02
+    @unittest.skipUnless(HAVE_LUKS2, "Integrity not supported")
940a02
+    def test_integrity_wipe(self):
940a02
+        # also check that wipe progress reporting works
940a02
+        progress_log = []
940a02
+
940a02
+        def _my_progress_func(_task, _status, completion, msg):
940a02
+            progress_log.append((completion, msg))
940a02
+
940a02
+        succ = BlockDev.utils_init_prog_reporting(_my_progress_func)
940a02
+        self.assertTrue(succ)
940a02
+        self.addCleanup(BlockDev.utils_init_prog_reporting, None)
940a02
+
940a02
+        succ = BlockDev.crypto_integrity_format(self.loop_dev, "sha256", True)
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        # at least one message "Integrity device wipe in progress" should be logged
940a02
+        self.assertTrue(any(prog[1] == "Integrity device wipe in progress" for prog in progress_log))
940a02
+
940a02
+        succ = BlockDev.crypto_integrity_open(self.loop_dev, self._dm_name, "sha256")
940a02
+        self.assertTrue(succ)
940a02
+        self.assertTrue(os.path.exists("/dev/mapper/%s" % self._dm_name))
940a02
+
940a02
+        # check the devices was wiped and the checksums recalculated
940a02
+        # (mkfs reads some blocks first so without checksums it would fail)
940a02
+        ret, _out, err = run_command("mkfs.ext2 /dev/mapper/%s " % self._dm_name)
940a02
+        self.assertEqual(ret, 0, msg="Failed to create ext2 filesystem on integrity: %s" % err)
940a02
+
940a02
+        succ = BlockDev.crypto_integrity_close(self._dm_name)
940a02
+        self.assertTrue(succ)
940a02
+        self.assertFalse(os.path.exists("/dev/mapper/%s" % self._dm_name))
940a02
-- 
940a02
2.31.1
940a02
940a02
940a02
From 4dcb7a42a2cb33f7a63021d72889c9a9688adfd3 Mon Sep 17 00:00:00 2001
940a02
From: Vojtech Trefny <vtrefny@redhat.com>
940a02
Date: Thu, 30 Sep 2021 16:01:40 +0200
940a02
Subject: [PATCH 2/3] Create smaller test images for integrity tests
940a02
940a02
We are going to overwrite the entire device in test_integrity_wipe
940a02
so we need to make sure the sparse actually fits to /tmp which
940a02
can be smaller than 1 GiB.
940a02
---
940a02
 tests/crypto_test.py | 6 ++++--
940a02
 1 file changed, 4 insertions(+), 2 deletions(-)
940a02
940a02
diff --git a/tests/crypto_test.py b/tests/crypto_test.py
940a02
index 1c6832e..b7ec251 100644
940a02
--- a/tests/crypto_test.py
940a02
+++ b/tests/crypto_test.py
940a02
@@ -44,6 +44,7 @@ class CryptoTestCase(unittest.TestCase):
940a02
     requested_plugins = BlockDev.plugin_specs_from_names(("crypto", "loop"))
940a02
 
940a02
     _dm_name = "libblockdevTestLUKS"
940a02
+    _sparse_size = 1024**3
940a02
 
940a02
     @classmethod
940a02
     def setUpClass(cls):
940a02
@@ -57,8 +58,8 @@ class CryptoTestCase(unittest.TestCase):
940a02
 
940a02
     def setUp(self):
940a02
         self.addCleanup(self._clean_up)
940a02
-        self.dev_file = create_sparse_tempfile("crypto_test", 1024**3)
940a02
-        self.dev_file2 = create_sparse_tempfile("crypto_test2", 1024**3)
940a02
+        self.dev_file = create_sparse_tempfile("crypto_test", self._sparse_size)
940a02
+        self.dev_file2 = create_sparse_tempfile("crypto_test2", self._sparse_size)
940a02
         try:
940a02
             self.loop_dev = create_lio_device(self.dev_file)
940a02
         except RuntimeError as e:
940a02
@@ -1160,6 +1161,7 @@ class CryptoTestBitlk(CryptoTestCase):
940a02
 class CryptoTestIntegrity(CryptoTestCase):
940a02
 
940a02
     _dm_name = "libblockdevTestIntegrity"
940a02
+    _sparse_size = 100 * 1024**2
940a02
 
940a02
     @unittest.skipUnless(HAVE_LUKS2, "Integrity not supported")
940a02
     def test_integrity(self):
940a02
-- 
940a02
2.31.1
940a02
940a02
940a02
From 3b82f9085c0df2e58b673716cdefd747495738e2 Mon Sep 17 00:00:00 2001
940a02
From: Vojtech Trefny <vtrefny@redhat.com>
940a02
Date: Wed, 20 Oct 2021 10:27:41 +0200
940a02
Subject: [PATCH 3/3] crypto: Do not use libcryptsetup flags directly in
940a02
 crypto.h
940a02
940a02
We can "translate" our flags in the implementation instead to
940a02
avoid including libcryptsetup.h in our header and API files.
940a02
---
940a02
 src/lib/plugin_apis/crypto.api | 17 ++++++-----------
940a02
 src/plugins/crypto.c           | 34 +++++++++++++++++++++++++++++++++-
940a02
 src/plugins/crypto.h           | 16 ++++++----------
940a02
 tests/crypto_test.py           | 14 ++++++++++++++
940a02
 4 files changed, 59 insertions(+), 22 deletions(-)
940a02
940a02
diff --git a/src/lib/plugin_apis/crypto.api b/src/lib/plugin_apis/crypto.api
940a02
index 40e32c8..cf87979 100644
940a02
--- a/src/lib/plugin_apis/crypto.api
940a02
+++ b/src/lib/plugin_apis/crypto.api
940a02
@@ -1,6 +1,5 @@
940a02
 #include <glib.h>
940a02
 #include <blockdev/utils.h>
940a02
-#include <libcryptsetup.h>
940a02
 
940a02
 #define BD_CRYPTO_LUKS_METADATA_SIZE G_GUINT64_CONSTANT (2097152ULL) // 2 MiB
940a02
 
940a02
@@ -343,16 +342,12 @@ GType bd_crypto_integrity_extra_get_type () {
940a02
 }
940a02
 
940a02
 typedef enum {
940a02
-    BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL         = CRYPT_ACTIVATE_NO_JOURNAL,
940a02
-    BD_CRYPTO_INTEGRITY_OPEN_RECOVERY           = CRYPT_ACTIVATE_RECOVERY,
940a02
-#ifdef CRYPT_ACTIVATE_NO_JOURNAL_BITMAP
940a02
-    BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL_BITMAP  = CRYPT_ACTIVATE_NO_JOURNAL_BITMAP,
940a02
-#endif
940a02
-    BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE        = CRYPT_ACTIVATE_RECALCULATE,
940a02
-#ifdef CRYPT_ACTIVATE_RECALCULATE_RESET
940a02
-    BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE_RESET  = CRYPT_ACTIVATE_RECALCULATE_RESET,
940a02
-#endif
940a02
-    BD_CRYPTO_INTEGRITY_OPEN_ALLOW_DISCARDS     = CRYPT_ACTIVATE_ALLOW_DISCARDS,
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL         = 1 << 0,
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_RECOVERY           = 1 << 1,
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL_BITMAP  = 1 << 2,
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE        = 1 << 3,
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE_RESET  = 1 << 4,
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_ALLOW_DISCARDS     = 1 << 5,
940a02
 } BDCryptoIntegrityOpenFlags;
940a02
 
940a02
 #define BD_CRYPTO_TYPE_LUKS_INFO (bd_crypto_luks_info_get_type ())
940a02
diff --git a/src/plugins/crypto.c b/src/plugins/crypto.c
940a02
index b1b0700..8a4d64a 100644
940a02
--- a/src/plugins/crypto.c
940a02
+++ b/src/plugins/crypto.c
940a02
@@ -2223,6 +2223,7 @@ gboolean bd_crypto_integrity_open (const gchar *device, const gchar *name, const
940a02
     guint64 progress_id = 0;
940a02
     gchar *msg = NULL;
940a02
     struct crypt_params_integrity params = ZERO_INIT;
940a02
+    guint32 activate_flags = 0;
940a02
 
940a02
     params.integrity = algorithm;
940a02
     params.integrity_key_size = key_size;
940a02
@@ -2237,6 +2238,37 @@ gboolean bd_crypto_integrity_open (const gchar *device, const gchar *name, const
940a02
         params.buffer_sectors = extra->buffer_sectors;
940a02
     }
940a02
 
940a02
+
940a02
+    if (flags & BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL)
940a02
+        activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
940a02
+    if (flags & BD_CRYPTO_INTEGRITY_OPEN_RECOVERY)
940a02
+        activate_flags |= CRYPT_ACTIVATE_RECOVERY;
940a02
+    if (flags & BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE)
940a02
+        activate_flags |= CRYPT_ACTIVATE_RECALCULATE;
940a02
+    if (flags & BD_CRYPTO_INTEGRITY_OPEN_ALLOW_DISCARDS)
940a02
+        activate_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
940a02
+    if (flags & BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL_BITMAP) {
940a02
+#ifndef CRYPT_ACTIVATE_NO_JOURNAL_BITMAP
940a02
+        g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
940a02
+                     "Cannot activate %s with bitmap, installed version of cryptsetup doesn't support this option.", device);
940a02
+        bd_utils_report_finished (progress_id, (*error)->message);
940a02
+        return FALSE;
940a02
+#else
940a02
+        activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL_BITMAP;
940a02
+#endif
940a02
+    }
940a02
+
940a02
+    if (flags & BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE_RESET) {
940a02
+#ifndef CRYPT_ACTIVATE_RECALCULATE_RESET
940a02
+        g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
940a02
+                     "Cannot reset integrity recalculation while activating %s, installed version of cryptsetup doesn't support this option.", device);
940a02
+        bd_utils_report_finished (progress_id, (*error)->message);
940a02
+        return FALSE;
940a02
+#else
940a02
+        activate_flags |= CRYPT_ACTIVATE_RECALCULATE_RESET;
940a02
+#endif
940a02
+    }
940a02
+
940a02
     msg = g_strdup_printf ("Started opening '%s' integrity device", device);
940a02
     progress_id = bd_utils_report_started (msg);
940a02
     g_free (msg);
940a02
@@ -2258,7 +2290,7 @@ gboolean bd_crypto_integrity_open (const gchar *device, const gchar *name, const
940a02
         return FALSE;
940a02
     }
940a02
 
940a02
-    ret = crypt_activate_by_volume_key (cd, name, (const char *) key_data, key_size, flags);
940a02
+    ret = crypt_activate_by_volume_key (cd, name, (const char *) key_data, key_size, activate_flags);
940a02
     if (ret < 0) {
940a02
         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
940a02
                      "Failed to activate device: %s", strerror_l (-ret, c_locale));
940a02
diff --git a/src/plugins/crypto.h b/src/plugins/crypto.h
940a02
index 166e558..b5f133c 100644
940a02
--- a/src/plugins/crypto.h
940a02
+++ b/src/plugins/crypto.h
940a02
@@ -141,16 +141,12 @@ BDCryptoIntegrityExtra* bd_crypto_integrity_extra_copy (BDCryptoIntegrityExtra *
940a02
 BDCryptoIntegrityExtra* bd_crypto_integrity_extra_new (guint64 sector_size, guint64 journal_size, guint journal_watermark, guint journal_commit_time, guint64 interleave_sectors, guint64 tag_size, guint64 buffer_sectors);
940a02
 
940a02
 typedef enum {
940a02
-    BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL         = CRYPT_ACTIVATE_NO_JOURNAL,
940a02
-    BD_CRYPTO_INTEGRITY_OPEN_RECOVERY           = CRYPT_ACTIVATE_RECOVERY,
940a02
-#ifdef CRYPT_ACTIVATE_NO_JOURNAL_BITMAP
940a02
-    BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL_BITMAP  = CRYPT_ACTIVATE_NO_JOURNAL_BITMAP,
940a02
-#endif
940a02
-    BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE        = CRYPT_ACTIVATE_RECALCULATE,
940a02
-#ifdef CRYPT_ACTIVATE_RECALCULATE_RESET
940a02
-    BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE_RESET  = CRYPT_ACTIVATE_RECALCULATE_RESET,
940a02
-#endif
940a02
-    BD_CRYPTO_INTEGRITY_OPEN_ALLOW_DISCARDS     = CRYPT_ACTIVATE_ALLOW_DISCARDS,
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL         = 1 << 0,
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_RECOVERY           = 1 << 1,
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL_BITMAP  = 1 << 2,
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE        = 1 << 3,
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE_RESET  = 1 << 4,
940a02
+    BD_CRYPTO_INTEGRITY_OPEN_ALLOW_DISCARDS     = 1 << 5,
940a02
 } BDCryptoIntegrityOpenFlags;
940a02
 
940a02
 /**
940a02
diff --git a/tests/crypto_test.py b/tests/crypto_test.py
940a02
index b7ec251..673d8b8 100644
940a02
--- a/tests/crypto_test.py
940a02
+++ b/tests/crypto_test.py
940a02
@@ -1215,6 +1215,20 @@ class CryptoTestIntegrity(CryptoTestCase):
940a02
         self.assertTrue(succ)
940a02
         self.assertFalse(os.path.exists("/dev/mapper/%s" % self._dm_name))
940a02
 
940a02
+        # open with flags
940a02
+        succ = BlockDev.crypto_integrity_open(self.loop_dev, self._dm_name, "crc32c",
940a02
+                                              flags=BlockDev.CryptoIntegrityOpenFlags.ALLOW_DISCARDS)
940a02
+        self.assertTrue(succ)
940a02
+        self.assertTrue(os.path.exists("/dev/mapper/%s" % self._dm_name))
940a02
+
940a02
+        # check that discard is enabled for the mapped device
940a02
+        _ret, out, _err = run_command("dmsetup table %s" % self._dm_name)
940a02
+        self.assertIn("allow_discards", out)
940a02
+
940a02
+        succ = BlockDev.crypto_integrity_close(self._dm_name)
940a02
+        self.assertTrue(succ)
940a02
+        self.assertFalse(os.path.exists("/dev/mapper/%s" % self._dm_name))
940a02
+
940a02
     @tag_test(TestTags.SLOW)
940a02
     @unittest.skipUnless(HAVE_LUKS2, "Integrity not supported")
940a02
     def test_integrity_wipe(self):
940a02
-- 
940a02
2.31.1
940a02