From 138da3e73ab52fefe6419052c5b2d58f2ca0b3f1 Mon Sep 17 00:00:00 2001 From: Daniel Zatovic Date: Fri, 10 Mar 2023 11:19:33 +0100 Subject: [PATCH] Allow linking VK to a user-specified keyring. Add a new API crypt_set_keyring_to_link nad CLI option --link-vk-to-keyring. This allows the user to specify ID of the keyring where the VK should be linked. --- lib/libcryptsetup.h | 8 ++++++++ lib/libcryptsetup.sym | 1 + lib/setup.c | 20 ++++++++++++++++++++ lib/utils_keyring.c | 38 ++++++++++++++++++++++++++++++++++++++ lib/utils_keyring.h | 1 + src/cryptsetup.c | 11 +++++++++++ src/cryptsetup_arg_list.h | 2 ++ src/cryptsetup_args.h | 1 + src/utils_arg_names.h | 1 + 9 files changed, 83 insertions(+) diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index ef2ac2cb..822028ab 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -3028,6 +3028,14 @@ void *crypt_safe_realloc(void *data, size_t size); */ void crypt_safe_memzero(void *data, size_t size); +/** + * Link the volume key to the specified keyring. + * + * @param cd crypt device handle + * @param keyring_to_link_vk the ID of the keyring in which volume key should be linked + */ +void crypt_set_keyring_to_link(struct crypt_device *cd, int keyring_to_link_vk); + /** @} */ #ifdef __cplusplus diff --git a/lib/libcryptsetup.sym b/lib/libcryptsetup.sym index d907ce9a..a17b1157 100644 --- a/lib/libcryptsetup.sym +++ b/lib/libcryptsetup.sym @@ -174,5 +174,6 @@ CRYPTSETUP_2.7 { crypt_get_hw_encryption_key_size; crypt_keyslot_context_init_by_keyring; crypt_resume_by_keyslot_context; + crypt_set_keyring_to_link; crypt_wipe_hw_opal; } CRYPTSETUP_2.6; diff --git a/lib/setup.c b/lib/setup.c index 820fc0d6..d6e6d279 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -60,6 +60,9 @@ struct crypt_device { /* global context scope settings */ unsigned key_in_keyring:1; + bool link_vk_to_keyring; + int keyring_to_link_vk; + uint64_t data_offset; uint64_t metadata_size; /* Used in LUKS2 format */ uint64_t keyslots_size; /* Used in LUKS2 format */ @@ -7206,6 +7209,15 @@ int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key } else crypt_set_key_in_keyring(cd, 1); + if (!r && cd->link_vk_to_keyring) { + log_dbg(cd, "Linking volume key to the specified keyring"); + r = keyring_link_key_to_keyring(LOGON_KEY, vk->key_description, cd->keyring_to_link_vk); + if (r) { + log_err(cd, _("Failed to link key to the specified keyring.")); + log_dbg(cd, "The keyring_link_key_to_keyring function failed (error %d).", r); + } + } + return r; } @@ -7241,6 +7253,14 @@ void crypt_drop_keyring_key_by_description(struct crypt_device *cd, const char * crypt_set_key_in_keyring(cd, 0); } +void crypt_set_keyring_to_link(struct crypt_device *cd, int keyring_to_link_vk) +{ + if (cd) { + cd->link_vk_to_keyring = true; + cd->keyring_to_link_vk = keyring_to_link_vk; + } +} + /* internal only */ void crypt_drop_keyring_key(struct crypt_device *cd, struct volume_key *vks) { diff --git a/lib/utils_keyring.c b/lib/utils_keyring.c index 6061750c..4750c6a4 100644 --- a/lib/utils_keyring.c +++ b/lib/utils_keyring.c @@ -71,6 +71,12 @@ static long keyctl_read(key_serial_t key, char *buffer, size_t buflen) return syscall(__NR_keyctl, KEYCTL_READ, key, buffer, buflen); } +/* keyctl_link */ +static long keyctl_link(key_serial_t key, key_serial_t keyring) +{ + return syscall(__NR_keyctl, KEYCTL_LINK, key, keyring); +} + /* keyctl_unlink */ static long keyctl_unlink(key_serial_t key, key_serial_t keyring) { @@ -180,6 +186,33 @@ int keyring_get_passphrase(const char *key_desc, #endif } +static int keyring_link_key_to_keyring_key_type(const char *type_name, const char *key_desc, + key_serial_t keyring_to_link) +{ +#ifdef KERNEL_KEYRING + long r; + key_serial_t kid; + + if (!type_name || !key_desc) + return -EINVAL; + + do + kid = request_key(type_name, key_desc, NULL, 0); + while (kid < 0 && errno == EINTR); + + if (kid < 0) + return 0; + + r = keyctl_link(kid, keyring_to_link); + if (r < 0) + return -errno; + + return 0; +#else + return -ENOTSUP; +#endif +} + static int keyring_revoke_and_unlink_key_type(const char *type_name, const char *key_desc) { #ifdef KERNEL_KEYRING @@ -216,6 +249,11 @@ const char *key_type_name(key_type_t type) return NULL; } +int keyring_link_key_to_keyring(key_type_t ktype, const char *key_desc, key_serial_t keyring_to_link) +{ + return keyring_link_key_to_keyring_key_type(key_type_name(ktype), key_desc, keyring_to_link); +} + int keyring_revoke_and_unlink_key(key_type_t ktype, const char *key_desc) { return keyring_revoke_and_unlink_key_type(key_type_name(ktype), key_desc); diff --git a/lib/utils_keyring.h b/lib/utils_keyring.h index 0248862d..79424809 100644 --- a/lib/utils_keyring.h +++ b/lib/utils_keyring.h @@ -51,5 +51,6 @@ int keyring_add_key_in_user_keyring( size_t key_size); int keyring_revoke_and_unlink_key(key_type_t ktype, const char *key_desc); +int keyring_link_key_to_keyring(key_type_t ktype, const char *key_desc, int keyring_to_link); #endif diff --git a/src/cryptsetup.c b/src/cryptsetup.c index 6bed1589..39626564 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -1654,6 +1654,9 @@ static int action_open_luks(void) set_activation_flags(&activate_flags); + if (ARG_SET(OPT_LINK_VK_TO_KEYRING_ID)) + crypt_set_keyring_to_link(cd, ARG_INT32(OPT_LINK_VK_TO_KEYRING_ID)); + if (ARG_SET(OPT_VOLUME_KEY_FILE_ID)) { keysize = crypt_get_volume_key_size(cd); if (!keysize && !ARG_SET(OPT_KEY_SIZE_ID)) { @@ -2509,6 +2512,9 @@ static int action_luksResume(void) return r; r = -EINVAL; + if (ARG_SET(OPT_LINK_VK_TO_KEYRING_ID)) + crypt_set_keyring_to_link(cd, ARG_INT32(OPT_LINK_VK_TO_KEYRING_ID)); + if (!isLUKS(crypt_get_type(cd))) { log_err(_("%s is not active LUKS device name or header is missing."), action_argv[0]); goto out; @@ -3655,6 +3661,11 @@ int main(int argc, const char **argv) _("PBKDF forced iterations cannot be combined with iteration time option."), poptGetInvocationName(popt_context)); + if (ARG_SET(OPT_DISABLE_KEYRING_ID) && ARG_SET(OPT_LINK_VK_TO_KEYRING_ID)) + usage(popt_context, EXIT_FAILURE, + _("Cannot link volume key to a keyring when keyring is disabled."), + poptGetInvocationName(popt_context)); + if (ARG_SET(OPT_DEBUG_ID) || ARG_SET(OPT_DEBUG_JSON_ID)) { crypt_set_debug_level(ARG_SET(OPT_DEBUG_JSON_ID)? CRYPT_DEBUG_JSON : CRYPT_DEBUG_ALL); dbg_version_and_cmd(argc, argv); diff --git a/src/cryptsetup_arg_list.h b/src/cryptsetup_arg_list.h index 8a2a4c4c..534a707d 100644 --- a/src/cryptsetup_arg_list.h +++ b/src/cryptsetup_arg_list.h @@ -111,6 +111,8 @@ ARG(OPT_KEYSLOT_KEY_SIZE, '\0', POPT_ARG_STRING, N_("LUKS2 keyslot: The size of ARG(OPT_LABEL, '\0', POPT_ARG_STRING, N_("Set label for the LUKS2 device"), NULL, CRYPT_ARG_STRING, {}, OPT_LABEL_ACTIONS) +ARG(OPT_LINK_VK_TO_KEYRING, '\0', POPT_ARG_STRING, N_("Set keyring where to link volume key"), NULL, CRYPT_ARG_INT32, {}, OPT_LINK_VK_TO_KEYRING_ACTIONS) + ARG(OPT_LUKS2_KEYSLOTS_SIZE, '\0', POPT_ARG_STRING, N_("LUKS2 header keyslots area size"), N_("bytes"), CRYPT_ARG_UINT64, {}, OPT_LUKS2_KEYSLOTS_SIZE_ACTIONS) ARG(OPT_LUKS2_METADATA_SIZE, '\0', POPT_ARG_STRING, N_("LUKS2 header metadata area size"), N_("bytes"), CRYPT_ARG_UINT64, {}, OPT_LUKS2_METADATA_SIZE_ACTIONS) diff --git a/src/cryptsetup_args.h b/src/cryptsetup_args.h index e1d393fc..7e71a76d 100644 --- a/src/cryptsetup_args.h +++ b/src/cryptsetup_args.h @@ -75,6 +75,7 @@ #define OPT_NEW_KEY_SLOT_ACTIONS { ADDKEY_ACTION } #define OPT_NEW_TOKEN_ID_ACTIONS { ADDKEY_ACTION } #define OPT_LABEL_ACTIONS { CONFIG_ACTION, FORMAT_ACTION, REENCRYPT_ACTION } +#define OPT_LINK_VK_TO_KEYRING_ACTIONS { OPEN_ACTION, RESUME_ACTION } #define OPT_LUKS2_KEYSLOTS_SIZE_ACTIONS { REENCRYPT_ACTION, FORMAT_ACTION } #define OPT_LUKS2_METADATA_SIZE_ACTIONS { REENCRYPT_ACTION, FORMAT_ACTION } #define OPT_OFFSET_ACTIONS { OPEN_ACTION, REENCRYPT_ACTION, FORMAT_ACTION } diff --git a/src/utils_arg_names.h b/src/utils_arg_names.h index 33642176..f64f18b2 100644 --- a/src/utils_arg_names.h +++ b/src/utils_arg_names.h @@ -105,6 +105,7 @@ #define OPT_NO_WIPE "no-wipe" #define OPT_WIPE "wipe" #define OPT_LABEL "label" +#define OPT_LINK_VK_TO_KEYRING "link-vk-to-keyring" #define OPT_LUKS2_KEYSLOTS_SIZE "luks2-keyslots-size" #define OPT_LUKS2_METADATA_SIZE "luks2-metadata-size" #define OPT_MASTER_KEY_FILE "master-key-file"