From 8338945fc3db65d0d1cb07a7f583a0631dd8f412 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Mon, 1 Dec 2025 15:19:22 +0100 Subject: [PATCH] crypto: Allow using activate flags when opening a device This currently allows setting the device as read only and enabling discard for all types of devices supported by cryptsetup. Fixes: #1138 --- docs/libblockdev-sections.txt | 5 + src/lib/plugin_apis/crypto.api | 83 ++++++++++++++ src/plugins/crypto.c | 170 +++++++++++++++++++++++----- src/plugins/crypto.h | 9 ++ src/python/gi/overrides/BlockDev.py | 8 ++ tests/crypto_test.py | 82 ++++++++++++++ 6 files changed, 328 insertions(+), 29 deletions(-) diff --git a/docs/libblockdev-sections.txt b/docs/libblockdev-sections.txt index 97cb28e4..48f52edf 100644 --- a/docs/libblockdev-sections.txt +++ b/docs/libblockdev-sections.txt @@ -81,6 +81,8 @@ bd_crypto_keyslot_context_new_keyfile bd_crypto_keyslot_context_new_keyring bd_crypto_keyslot_context_new_volume_key bd_crypto_luks_open +BDCryptoOpenFlags +bd_crypto_luks_open_flags bd_crypto_luks_close bd_crypto_luks_add_key bd_crypto_luks_remove_key @@ -119,6 +121,7 @@ bd_crypto_luks_token_info_copy bd_crypto_luks_token_info bd_crypto_keyring_add_key bd_crypto_tc_open +bd_crypto_tc_open_flags bd_crypto_tc_close bd_crypto_escrow_device BDCryptoBITLKInfo @@ -126,8 +129,10 @@ bd_crypto_bitlk_info bd_crypto_bitlk_info_copy bd_crypto_bitlk_info_free bd_crypto_bitlk_open +bd_crypto_bitlk_open_flags bd_crypto_bitlk_close bd_crypto_fvault2_open +bd_crypto_fvault2_open_flags bd_crypto_fvault2_close bd_crypto_opal_is_supported bd_crypto_opal_wipe_device diff --git a/src/lib/plugin_apis/crypto.api b/src/lib/plugin_apis/crypto.api index 1c42604c..adf43ffc 100644 --- a/src/lib/plugin_apis/crypto.api +++ b/src/lib/plugin_apis/crypto.api @@ -361,6 +361,11 @@ typedef enum { BD_CRYPTO_INTEGRITY_OPEN_ALLOW_DISCARDS = 1 << 5, } BDCryptoIntegrityOpenFlags; +typedef enum { + BD_CRYPTO_OPEN_ALLOW_DISCARDS = 1 << 0, + BD_CRYPTO_OPEN_READONLY = 1 << 1, +} BDCryptoOpenFlags; + #define BD_CRYPTO_TYPE_LUKS_INFO (bd_crypto_luks_info_get_type ()) GType bd_crypto_luks_info_get_type(); @@ -939,6 +944,31 @@ gboolean bd_crypto_luks_format (const gchar *device, const gchar *cipher, guint6 */ gboolean bd_crypto_luks_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error); +/** + * bd_crypto_luks_open_flags: + * @device: the device to open + * @name: name for the LUKS device + * @context: key slot context (passphrase/keyfile/token...) to open this LUKS @device + * @flags: activation flags for the LUKS device + * @error: (out) (optional): place to store error (if any) + * + * Supported @context types for this function: passphrase, key file, keyring + * + * Returns: whether the @device was successfully opened or not + * + * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE + * + * Example of using %bd_crypto_luks_open_flags with %BDCryptoKeyslotContext: + * + * |[ + * BDCryptoKeyslotContext *context = NULL; + * + * context = bd_crypto_keyslot_context_new_passphrase ("passphrase", 10, NULL); + * bd_crypto_luks_open_flags ("/dev/vda1", "luks-device", context, 0, NULL); + * ]| + */ +gboolean bd_crypto_luks_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, BDCryptoOpenFlags flags, GError **error); + /** * bd_crypto_luks_close: * @luks_device: LUKS device to close @@ -1300,6 +1330,27 @@ gboolean bd_crypto_device_seems_encrypted (const gchar *device, GError **error); */ gboolean bd_crypto_tc_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, const gchar **keyfiles, gboolean hidden, gboolean system, gboolean veracrypt, guint32 veracrypt_pim, gboolean read_only, GError **error); +/** + * bd_crypto_tc_open_flags: + * @device: the device to open + * @name: name for the TrueCrypt/VeraCrypt device + * @context: (nullable): passphrase key slot context for this TrueCrypt/VeraCrypt volume + * @flags: activation flags for the TrueCrypt/VeraCrypt device + * @keyfiles: (nullable) (array zero-terminated=1): paths to the keyfiles for the TrueCrypt/VeraCrypt volume + * @hidden: whether a hidden volume inside the volume should be opened + * @system: whether to try opening as an encrypted system (with boot loader) + * @veracrypt: whether to try VeraCrypt modes (TrueCrypt modes are tried anyway) + * @veracrypt_pim: VeraCrypt PIM value (only used if @veracrypt is %TRUE) + * @error: (out) (optional): place to store error (if any) + * + * Supported @context types for this function: passphrase + * + * Returns: whether the @device was successfully opened or not + * + * Tech category: %BD_CRYPTO_TECH_TRUECRYPT-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE + */ +gboolean bd_crypto_tc_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, const gchar **keyfiles, gboolean hidden, gboolean system, gboolean veracrypt, guint32 veracrypt_pim, BDCryptoOpenFlags flags, GError **error); + /** * bd_crypto_tc_close: * @tc_device: TrueCrypt/VeraCrypt device to close @@ -1342,6 +1393,22 @@ gboolean bd_crypto_escrow_device (const gchar *device, const gchar *passphrase, */ gboolean bd_crypto_bitlk_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error); +/** + * bd_crypto_bitlk_open_flags: + * @device: the device to open + * @name: name for the BITLK device + * @context: key slot context (passphrase/keyfile/token...) for this BITLK device + * @flags: activation flags for the BITLK device + * @error: (out) (optional): place to store error (if any) + * + * Supported @context types for this function: passphrase, key file + * + * Returns: whether the @device was successfully opened or not + * + * Tech category: %BD_CRYPTO_TECH_BITLK-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE + */ +gboolean bd_crypto_bitlk_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, BDCryptoOpenFlags flags, GError **error); + /** * bd_crypto_bitlk_close: * @bitlk_device: BITLK device to close @@ -1369,6 +1436,22 @@ gboolean bd_crypto_bitlk_close (const gchar *bitlk_device, GError **error); */ gboolean bd_crypto_fvault2_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error); +/** + * bd_crypto_fvault2_open_flags: + * @device: the device to open + * @name: name for the FVAULT2 device + * @context: key slot context (passphrase/keyfile/token...) for this FVAULT2 volume + * @flags: activation flags for the FVAULT2 device + * @error: (out) (optional): place to store error (if any) + * + * Supported @context types for this function: passphrase, key file + * + * Returns: whether the @device was successfully opened or not + * + * Tech category: %BD_CRYPTO_TECH_FVAULT2-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE + */ +gboolean bd_crypto_fvault2_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, BDCryptoOpenFlags flags, GError **error); + /** * bd_crypto_fvault2_close: * @fvault2_device: FVAULT2 device to close diff --git a/src/plugins/crypto.c b/src/plugins/crypto.c index 31953d67..d5c9b64c 100644 --- a/src/plugins/crypto.c +++ b/src/plugins/crypto.c @@ -1262,11 +1262,11 @@ static gboolean _is_dm_name_valid (const gchar *name, GError **error) { } /** - * bd_crypto_luks_open: + * bd_crypto_luks_open_flags: * @device: the device to open * @name: name for the LUKS device * @context: key slot context (passphrase/keyfile/token...) to open this LUKS @device - * @read_only: whether to open as read-only or not (meaning read-write) + * @flags: activation flags for the LUKS device * @error: (out) (optional): place to store error (if any) * * Supported @context types for this function: passphrase, key file, keyring @@ -1275,16 +1275,16 @@ static gboolean _is_dm_name_valid (const gchar *name, GError **error) { * * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE * - * Example of using %bd_crypto_luks_open with %BDCryptoKeyslotContext: + * Example of using %bd_crypto_luks_open_flags with %BDCryptoKeyslotContext: * * |[ * BDCryptoKeyslotContext *context = NULL; * * context = bd_crypto_keyslot_context_new_passphrase ("passphrase", 10, NULL); - * bd_crypto_luks_open ("/dev/vda1", "luks-device", context, FALSE, NULL); + * bd_crypto_luks_open_flags ("/dev/vda1", "luks-device", context, 0, NULL); * ]| */ -gboolean bd_crypto_luks_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error) { +gboolean bd_crypto_luks_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, BDCryptoOpenFlags flags, GError **error) { struct crypt_device *cd = NULL; gchar *key_buffer = NULL; gsize buf_len = 0; @@ -1292,6 +1292,7 @@ gboolean bd_crypto_luks_open (const gchar *device, const gchar *name, BDCryptoKe guint64 progress_id = 0; gchar *msg = NULL; GError *l_error = NULL; + guint32 crypt_flags = 0; if (!_is_dm_name_valid (name, error)) return FALSE; @@ -1319,11 +1320,16 @@ gboolean bd_crypto_luks_open (const gchar *device, const gchar *name, BDCryptoKe return FALSE; } + if (flags & BD_CRYPTO_OPEN_ALLOW_DISCARDS) + crypt_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS; + if (flags & BD_CRYPTO_OPEN_READONLY) + crypt_flags |= CRYPT_ACTIVATE_READONLY; + if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) { ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT, (const char *) context->u.passphrase.pass_data, context->u.passphrase.data_len, - read_only ? CRYPT_ACTIVATE_READONLY : 0); + crypt_flags); } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) { ret = crypt_keyfile_device_read (cd, context->u.keyfile.keyfile, &key_buffer, &buf_len, context->u.keyfile.keyfile_offset, context->u.keyfile.key_size, 0); @@ -1335,12 +1341,10 @@ gboolean bd_crypto_luks_open (const gchar *device, const gchar *name, BDCryptoKe g_propagate_error (error, l_error); return FALSE; } - ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT, key_buffer, buf_len, - read_only ? CRYPT_ACTIVATE_READONLY : 0); + ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT, key_buffer, buf_len, crypt_flags); crypt_safe_free (key_buffer); } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYRING) - ret = crypt_activate_by_keyring (cd, name, context->u.keyring.key_desc, CRYPT_ANY_SLOT, - read_only ? CRYPT_ACTIVATE_READONLY : 0); + ret = crypt_activate_by_keyring (cd, name, context->u.keyring.key_desc, CRYPT_ANY_SLOT, crypt_flags); else { g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT, "Only 'passphrase', 'key file' and 'keyring' context types are valid for LUKS open."); @@ -1369,6 +1373,33 @@ gboolean bd_crypto_luks_open (const gchar *device, const gchar *name, BDCryptoKe return TRUE; } +/** + * bd_crypto_luks_open: + * @device: the device to open + * @name: name for the LUKS device + * @context: key slot context (passphrase/keyfile/token...) to open this LUKS @device + * @read_only: whether to open as read-only or not (meaning read-write) + * @error: (out) (optional): place to store error (if any) + * + * Supported @context types for this function: passphrase, key file, keyring + * + * Returns: whether the @device was successfully opened or not + * + * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE + * + * Example of using %bd_crypto_luks_open with %BDCryptoKeyslotContext: + * + * |[ + * BDCryptoKeyslotContext *context = NULL; + * + * context = bd_crypto_keyslot_context_new_passphrase ("passphrase", 10, NULL); + * bd_crypto_luks_open ("/dev/vda1", "luks-device", context, FALSE, NULL); + * ]| + */ +gboolean bd_crypto_luks_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error) { + return bd_crypto_luks_open_flags (device, name, context, read_only ? BD_CRYPTO_OPEN_READONLY : 0, error); +} + static gboolean _crypto_close (const gchar *device, const gchar *tech_name, GError **error) { struct crypt_device *cd = NULL; gint ret = 0; @@ -3160,11 +3191,11 @@ gboolean bd_crypto_device_seems_encrypted (const gchar *device, GError **error) } /** - * bd_crypto_tc_open: + * bd_crypto_tc_open_flags: * @device: the device to open * @name: name for the TrueCrypt/VeraCrypt device * @context: (nullable): passphrase key slot context for this TrueCrypt/VeraCrypt volume - * @read_only: whether to open as read-only or not (meaning read-write) + * @flags: activation flags for the TrueCrypt/VeraCrypt device * @keyfiles: (nullable) (array zero-terminated=1): paths to the keyfiles for the TrueCrypt/VeraCrypt volume * @hidden: whether a hidden volume inside the volume should be opened * @system: whether to try opening as an encrypted system (with boot loader) @@ -3178,7 +3209,7 @@ gboolean bd_crypto_device_seems_encrypted (const gchar *device, GError **error) * * Tech category: %BD_CRYPTO_TECH_TRUECRYPT-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE */ -gboolean bd_crypto_tc_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, const gchar **keyfiles, gboolean hidden, gboolean system, gboolean veracrypt, guint32 veracrypt_pim, gboolean read_only, GError **error) { +gboolean bd_crypto_tc_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, const gchar **keyfiles, gboolean hidden, gboolean system, gboolean veracrypt, guint32 veracrypt_pim, BDCryptoOpenFlags flags, GError **error) { struct crypt_device *cd = NULL; gint ret = 0; guint64 progress_id = 0; @@ -3187,6 +3218,7 @@ gboolean bd_crypto_tc_open (const gchar *device, const gchar *name, BDCryptoKeys gsize keyfiles_count = 0; guint i; GError *l_error = NULL; + guint32 crypt_flags = 0; if (!_is_dm_name_valid (name, error)) return FALSE; @@ -3250,9 +3282,12 @@ gboolean bd_crypto_tc_open (const gchar *device, const gchar *name, BDCryptoKeys return FALSE; } - ret = crypt_activate_by_volume_key (cd, name, NULL, 0, - read_only ? CRYPT_ACTIVATE_READONLY : 0); + if (flags & BD_CRYPTO_OPEN_ALLOW_DISCARDS) + crypt_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS; + if (flags & BD_CRYPTO_OPEN_READONLY) + crypt_flags |= CRYPT_ACTIVATE_READONLY; + ret = crypt_activate_by_volume_key (cd, name, NULL, 0, crypt_flags); if (ret < 0) { g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE, "Failed to activate device: %s", strerror_l (-ret, c_locale)); @@ -3267,6 +3302,29 @@ gboolean bd_crypto_tc_open (const gchar *device, const gchar *name, BDCryptoKeys return TRUE; } +/** + * bd_crypto_tc_open: + * @device: the device to open + * @name: name for the TrueCrypt/VeraCrypt device + * @context: (nullable): passphrase key slot context for this TrueCrypt/VeraCrypt volume + * @read_only: whether to open as read-only or not (meaning read-write) + * @keyfiles: (nullable) (array zero-terminated=1): paths to the keyfiles for the TrueCrypt/VeraCrypt volume + * @hidden: whether a hidden volume inside the volume should be opened + * @system: whether to try opening as an encrypted system (with boot loader) + * @veracrypt: whether to try VeraCrypt modes (TrueCrypt modes are tried anyway) + * @veracrypt_pim: VeraCrypt PIM value (only used if @veracrypt is %TRUE) + * @error: (out) (optional): place to store error (if any) + * + * Supported @context types for this function: passphrase + * + * Returns: whether the @device was successfully opened or not + * + * Tech category: %BD_CRYPTO_TECH_TRUECRYPT-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE + */ +gboolean bd_crypto_tc_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, const gchar **keyfiles, gboolean hidden, gboolean system, gboolean veracrypt, guint32 veracrypt_pim, gboolean read_only, GError **error) { + return bd_crypto_tc_open_flags (device, name, context, keyfiles, hidden, system, veracrypt, veracrypt_pim, read_only ? BD_CRYPTO_OPEN_READONLY : 0, error); +} + /** * bd_crypto_tc_close: * @tc_device: TrueCrypt/VeraCrypt device to close @@ -3528,11 +3586,11 @@ gboolean bd_crypto_escrow_device (const gchar *device, const gchar *passphrase, #endif /* WITH_BD_ESCROW */ /** - * bd_crypto_bitlk_open: + * bd_crypto_bitlk_open_flags: * @device: the device to open * @name: name for the BITLK device * @context: key slot context (passphrase/keyfile/token...) for this BITLK device - * @read_only: whether to open as read-only or not (meaning read-write) + * @flags: activation flags for the BITLK device * @error: (out) (optional): place to store error (if any) * * Supported @context types for this function: passphrase, key file @@ -3541,7 +3599,7 @@ gboolean bd_crypto_escrow_device (const gchar *device, const gchar *passphrase, * * Tech category: %BD_CRYPTO_TECH_BITLK-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE */ -gboolean bd_crypto_bitlk_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error) { +gboolean bd_crypto_bitlk_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, BDCryptoOpenFlags flags, GError **error) { struct crypt_device *cd = NULL; gint ret = 0; guint64 progress_id = 0; @@ -3549,6 +3607,7 @@ gboolean bd_crypto_bitlk_open (const gchar *device, const gchar *name, BDCryptoK GError *l_error = NULL; gchar *key_buffer = NULL; gsize buf_len = 0; + guint32 crypt_flags = 0; if (!_is_dm_name_valid (name, error)) return FALSE; @@ -3576,11 +3635,16 @@ gboolean bd_crypto_bitlk_open (const gchar *device, const gchar *name, BDCryptoK return FALSE; } + if (flags & BD_CRYPTO_OPEN_ALLOW_DISCARDS) + crypt_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS; + if (flags & BD_CRYPTO_OPEN_READONLY) + crypt_flags |= CRYPT_ACTIVATE_READONLY; + if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) { ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT, (const char *) context->u.passphrase.pass_data, context->u.passphrase.data_len, - read_only ? CRYPT_ACTIVATE_READONLY : 0); + crypt_flags); } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) { ret = crypt_keyfile_device_read (cd, context->u.keyfile.keyfile, &key_buffer, &buf_len, context->u.keyfile.keyfile_offset, context->u.keyfile.key_size, 0); @@ -3592,8 +3656,7 @@ gboolean bd_crypto_bitlk_open (const gchar *device, const gchar *name, BDCryptoK g_propagate_error (error, l_error); return FALSE; } - ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT, key_buffer, buf_len, - read_only ? CRYPT_ACTIVATE_READONLY : 0); + ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT, key_buffer, buf_len, crypt_flags); crypt_safe_free (key_buffer); } else { g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT, @@ -3623,6 +3686,24 @@ gboolean bd_crypto_bitlk_open (const gchar *device, const gchar *name, BDCryptoK return TRUE; } +/** + * bd_crypto_bitlk_open: + * @device: the device to open + * @name: name for the BITLK device + * @context: key slot context (passphrase/keyfile/token...) for this BITLK device + * @read_only: whether to open as read-only or not (meaning read-write) + * @error: (out) (optional): place to store error (if any) + * + * Supported @context types for this function: passphrase, key file + * + * Returns: whether the @device was successfully opened or not + * + * Tech category: %BD_CRYPTO_TECH_BITLK-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE + */ +gboolean bd_crypto_bitlk_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error) { + return bd_crypto_bitlk_open_flags (device, name, context, read_only ? BD_CRYPTO_OPEN_READONLY : 0, error); +} + /** * bd_crypto_bitlk_close: * @bitlk_device: BITLK device to close @@ -3637,11 +3718,11 @@ gboolean bd_crypto_bitlk_close (const gchar *bitlk_device, GError **error) { } /** - * bd_crypto_fvault2_open: + * bd_crypto_fvault2_open_flags: * @device: the device to open * @name: name for the FVAULT2 device * @context: key slot context (passphrase/keyfile/token...) for this FVAULT2 volume - * @read_only: whether to open as read-only or not (meaning read-write) + * @flags: activation flags for the FVAULT2 device * @error: (out) (optional): place to store error (if any) * * Supported @context types for this function: passphrase, key file @@ -3651,12 +3732,12 @@ gboolean bd_crypto_bitlk_close (const gchar *bitlk_device, GError **error) { * Tech category: %BD_CRYPTO_TECH_FVAULT2-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE */ #ifndef LIBCRYPTSETUP_26 -gboolean bd_crypto_fvault2_open (const gchar *device G_GNUC_UNUSED, const gchar *name G_GNUC_UNUSED, BDCryptoKeyslotContext *context G_GNUC_UNUSED, - gboolean read_only G_GNUC_UNUSED, GError **error) { +gboolean bd_crypto_fvault2_open_flags (const gchar *device G_GNUC_UNUSED, const gchar *name G_GNUC_UNUSED, BDCryptoKeyslotContext *context G_GNUC_UNUSED, + BDCryptoOpenFlags flags G_GNUC_UNUSED, GError **error) { /* this will return FALSE and set error, because FVAULT2 technology is not available */ return bd_crypto_is_tech_avail (BD_CRYPTO_TECH_FVAULT2, BD_CRYPTO_TECH_MODE_OPEN_CLOSE, error); #else -gboolean bd_crypto_fvault2_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error) { +gboolean bd_crypto_fvault2_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, BDCryptoOpenFlags flags, GError **error) { struct crypt_device *cd = NULL; gint ret = 0; guint64 progress_id = 0; @@ -3664,6 +3745,7 @@ gboolean bd_crypto_fvault2_open (const gchar *device, const gchar *name, BDCrypt GError *l_error = NULL; gchar *key_buffer = NULL; gsize buf_len = 0; + guint32 crypt_flags = 0; if (!_is_dm_name_valid (name, error)) return FALSE; @@ -3691,11 +3773,16 @@ gboolean bd_crypto_fvault2_open (const gchar *device, const gchar *name, BDCrypt return FALSE; } + if (flags & BD_CRYPTO_OPEN_ALLOW_DISCARDS) + crypt_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS; + if (flags & BD_CRYPTO_OPEN_READONLY) + crypt_flags |= CRYPT_ACTIVATE_READONLY; + if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) { ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT, (const char *) context->u.passphrase.pass_data, context->u.passphrase.data_len, - read_only ? CRYPT_ACTIVATE_READONLY : 0); + crypt_flags); } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) { ret = crypt_keyfile_device_read (cd, context->u.keyfile.keyfile, &key_buffer, &buf_len, context->u.keyfile.keyfile_offset, context->u.keyfile.key_size, 0); @@ -3707,8 +3794,7 @@ gboolean bd_crypto_fvault2_open (const gchar *device, const gchar *name, BDCrypt g_propagate_error (error, l_error); return FALSE; } - ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT, key_buffer, buf_len, - read_only ? CRYPT_ACTIVATE_READONLY : 0); + ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT, key_buffer, buf_len, crypt_flags); crypt_safe_free (key_buffer); } else { g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT, @@ -3739,6 +3825,32 @@ gboolean bd_crypto_fvault2_open (const gchar *device, const gchar *name, BDCrypt #endif } +/** + * bd_crypto_fvault2_open: + * @device: the device to open + * @name: name for the FVAULT2 device + * @context: key slot context (passphrase/keyfile/token...) for this FVAULT2 volume + * @read_only: whether to open as read-only or not (meaning read-write) + * @error: (out) (optional): place to store error (if any) + * + * Supported @context types for this function: passphrase, key file + * + * Returns: whether the @device was successfully opened or not + * + * Tech category: %BD_CRYPTO_TECH_FVAULT2-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE + */ +#ifndef LIBCRYPTSETUP_26 +gboolean bd_crypto_fvault2_open (const gchar *device G_GNUC_UNUSED, const gchar *name G_GNUC_UNUSED, BDCryptoKeyslotContext *context G_GNUC_UNUSED, + gboolean read_only G_GNUC_UNUSED, GError **error) { + /* this will return FALSE and set error, because FVAULT2 technology is not available */ + return bd_crypto_is_tech_avail (BD_CRYPTO_TECH_FVAULT2, BD_CRYPTO_TECH_MODE_OPEN_CLOSE, error); +} +#else +gboolean bd_crypto_fvault2_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error) { + return bd_crypto_fvault2_open_flags (device, name, context, read_only ? BD_CRYPTO_OPEN_READONLY : 0, error); +} +#endif + /** * bd_crypto_fvault2_close: * @fvault2_device: FVAULT2 device to close diff --git a/src/plugins/crypto.h b/src/plugins/crypto.h index b174724c..892866a1 100644 --- a/src/plugins/crypto.h +++ b/src/plugins/crypto.h @@ -172,6 +172,11 @@ typedef enum { BD_CRYPTO_LUKS_ACTIVATE_HIGH_PRIORITY = 1 << 6, } BDCryptoLUKSPersistentFlags; +typedef enum { + BD_CRYPTO_OPEN_ALLOW_DISCARDS = 1 << 0, + BD_CRYPTO_OPEN_READONLY = 1 << 1, +} BDCryptoOpenFlags; + /** * BDCryptoLUKSInfo: * @version: LUKS version @@ -290,6 +295,7 @@ const gchar* bd_crypto_luks_status (const gchar *luks_device, GError **error); gboolean bd_crypto_luks_format (const gchar *device, const gchar *cipher, guint64 key_size, BDCryptoKeyslotContext *context, guint64 min_entropy, BDCryptoLUKSVersion luks_version, BDCryptoLUKSExtra *extra,GError **error); gboolean bd_crypto_luks_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error); +gboolean bd_crypto_luks_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, BDCryptoOpenFlags flags, GError **error); gboolean bd_crypto_luks_close (const gchar *luks_device, GError **error); gboolean bd_crypto_luks_add_key (const gchar *device, BDCryptoKeyslotContext *context, BDCryptoKeyslotContext *ncontext, GError **error); gboolean bd_crypto_luks_remove_key (const gchar *device, BDCryptoKeyslotContext *context, GError **error); @@ -319,12 +325,15 @@ gboolean bd_crypto_keyring_add_key (const gchar *key_desc, const guint8 *key_dat gboolean bd_crypto_device_seems_encrypted (const gchar *device, GError **error); gboolean bd_crypto_tc_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, const gchar **keyfiles, gboolean hidden, gboolean system, gboolean veracrypt, guint32 veracrypt_pim, gboolean read_only, GError **error); +gboolean bd_crypto_tc_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, const gchar **keyfiles, gboolean hidden, gboolean system, gboolean veracrypt, guint32 veracrypt_pim, BDCryptoOpenFlags flags, GError **error); gboolean bd_crypto_tc_close (const gchar *tc_device, GError **error); gboolean bd_crypto_bitlk_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error); +gboolean bd_crypto_bitlk_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, BDCryptoOpenFlags flags, GError **error); gboolean bd_crypto_bitlk_close (const gchar *bitlk_device, GError **error); gboolean bd_crypto_fvault2_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error); +gboolean bd_crypto_fvault2_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, BDCryptoOpenFlags flags, GError **error); gboolean bd_crypto_fvault2_close (const gchar *fvault2_device, GError **error); gboolean bd_crypto_escrow_device (const gchar *device, const gchar *passphrase, const gchar *cert_data, const gchar *directory, const gchar *backup_passphrase, GError **error); diff --git a/src/python/gi/overrides/BlockDev.py b/src/python/gi/overrides/BlockDev.py index 15c963b9..b084dea4 100644 --- a/src/python/gi/overrides/BlockDev.py +++ b/src/python/gi/overrides/BlockDev.py @@ -336,6 +336,14 @@ def crypto_tc_open(device, name, passphrase, read_only=False, keyfiles=None, hid return _crypto_tc_open(device, name, passphrase, keyfiles, hidden, system, veracrypt, veracrypt_pim, read_only) __all__.append("crypto_tc_open") +_crypto_tc_open_flags = BlockDev.crypto_tc_open_flags +@override(BlockDev.crypto_tc_open_flags) +def crypto_tc_open_flags(device, name, passphrase, flags=0, keyfiles=None, hidden=False, system=False, veracrypt=False, veracrypt_pim=0): + if isinstance(passphrase, str): + passphrase = passphrase.encode("utf-8") + return _crypto_tc_open_flags(device, name, passphrase, keyfiles, hidden, system, veracrypt, veracrypt_pim, flags) +__all__.append("crypto_tc_open_flags") + _crypto_bitlk_open = BlockDev.crypto_bitlk_open @override(BlockDev.crypto_bitlk_open) def crypto_bitlk_open(device, name, passphrase, read_only=False): diff --git a/tests/crypto_test.py b/tests/crypto_test.py index 915eed86..f20a277f 100644 --- a/tests/crypto_test.py +++ b/tests/crypto_test.py @@ -117,6 +117,15 @@ def _is_fips_enabled(self): enabled = f.read() return enabled.strip() == "1" + def _is_ro(self, dm_name): + dm_path = os.path.realpath("/dev/mapper/%s" % dm_name) + dm_basename = os.path.basename(dm_path) + sysfs_path = "/sys/block/%s/ro" % dm_basename + + with open(sysfs_path, "r") as f: + ro = f.read() + return ro.strip() == "1" + class CryptoNoDevTestCase(CryptoTestCase): def setUp(self): # we don't need block devices for this test @@ -702,6 +711,35 @@ def test_luks_open_rw(self): def test_luks2_open_rw(self): self._luks_open_rw(self._luks2_format) +class CryptoTestLuksOpenFlags(CryptoTestCase): + def _luks_open_flags(self, create_fn): + """Verify that a LUKS device can be activated with flags""" + + create_fn(self.loop_devs[0], PASSWD, None, fast_pbkdf=True) + + ctx = BlockDev.CryptoKeyslotContext(passphrase=PASSWD) + succ = BlockDev.crypto_luks_open_flags(self.loop_devs[0], "libblockdevTestLUKS", ctx, + BlockDev.CryptoOpenFlags.ALLOW_DISCARDS | BlockDev.CryptoOpenFlags.READONLY) + self.assertTrue(succ) + + # check that discard is enabled for the mapped device + _ret, out, _err = run_command("dmsetup table %s" % self._dm_name) + self.assertIn("allow_discards", out) + + # check that the device is read-only + self.assertTrue(self._is_ro("libblockdevTestLUKS")) + + succ = BlockDev.crypto_luks_close("libblockdevTestLUKS") + self.assertTrue(succ) + + @tag_test(TestTags.SLOW) + def test_luks_open_flags(self): + self._luks_open_flags(self._luks_format) + + @tag_test(TestTags.SLOW) + def test_luks2_open_flags(self): + self._luks_open_flags(self._luks2_format) + class CryptoTestEscrow(CryptoTestCase): def setUp(self): # I am not able to generate a self-signed certificate that would work in FIPS @@ -1481,6 +1519,21 @@ def test_veracrypt_open_close(self): self.assertTrue(succ) self.assertFalse(os.path.exists("/dev/mapper/libblockdevTestTC")) + # open with flags + succ = BlockDev.crypto_tc_open_flags(self.vc_dev, "libblockdevTestTC", ctx, veracrypt=True, + flags=BlockDev.CryptoOpenFlags.ALLOW_DISCARDS | BlockDev.CryptoOpenFlags.READONLY) + self.assertTrue(succ) + + # check that discard is enabled for the mapped device + _ret, out, _err = run_command("dmsetup table libblockdevTestTC") + self.assertIn("allow_discards", out) + + # check that the device is read-only + self.assertTrue(self._is_ro("libblockdevTestTC")) + + succ = BlockDev.crypto_tc_close("libblockdevTestTC") + self.assertTrue(succ) + @tag_test(TestTags.NOSTORAGE) def test_seems_encrypted(self): """Verify that BlockDev.crypto_device_seems_encrypted works""" @@ -1581,6 +1634,21 @@ def test_bitlk_open_close(self): self.assertTrue(succ) self.assertFalse(os.path.exists("/dev/mapper/libblockdevTestBitlk")) + # open with flags + succ = BlockDev.crypto_bitlk_open_flags(self.bitlk_dev, "libblockdevTestBitlk", ctx, + BlockDev.CryptoOpenFlags.ALLOW_DISCARDS | BlockDev.CryptoOpenFlags.READONLY) + self.assertTrue(succ) + + # check that discard is enabled for the mapped device + _ret, out, _err = run_command("dmsetup table libblockdevTestBitlk") + self.assertIn("allow_discards", out) + + # check that the device is read-only + self.assertTrue(self._is_ro("libblockdevTestBitlk")) + + succ = BlockDev.crypto_bitlk_close("libblockdevTestBitlk") + self.assertTrue(succ) + @unittest.skipUnless(HAVE_BITLK, "BITLK not supported") def test_bitlk_info(self): """Verify that we get information about a BitLocker device""" @@ -1680,6 +1748,20 @@ def test_fvault2_open_close(self): self.assertTrue(succ) self.assertFalse(os.path.exists("/dev/mapper/libblockdevTestFVAULT2")) + # open with flags + succ = BlockDev.crypto_fvault2_open_flags(self.fvault2_dev, "libblockdevTestFVAULT2", ctx, + BlockDev.CryptoOpenFlags.ALLOW_DISCARDS | BlockDev.CryptoOpenFlags.READONLY) + self.assertTrue(succ) + + # check that discard is enabled for the mapped device + _ret, out, _err = run_command("dmsetup table libblockdevTestFVAULT2") + self.assertIn("allow_discards", out) + + # check that the device is read-only + self.assertTrue(self._is_ro("libblockdevTestFVAULT2")) + + succ = BlockDev.crypto_fvault2_close("libblockdevTestFVAULT2") + self.assertTrue(succ) class CryptoTestIntegrity(CryptoTestCase):