diff --git a/lib/keyslot_context.c b/lib/keyslot_context.c index b5566157..a72d0dba 100644 --- a/lib/keyslot_context.c +++ b/lib/keyslot_context.c @@ -362,6 +362,42 @@ static int get_luks1_volume_key_by_keyring(struct crypt_device *cd, return r; } +static int get_key_by_vk_in_keyring(struct crypt_device *cd, + struct crypt_keyslot_context *kc, + int keyslot __attribute__((unused)), + int segment __attribute__((unused)), + struct volume_key **r_vk) +{ + int r; + + assert(cd); + assert(kc && kc->type == CRYPT_KC_TYPE_VK_KEYRING); + assert(r_vk); + + r = keyring_read_by_id(kc->u.vk_kr.key_description, &kc->i_volume_key, &kc->i_volume_key_size); + if (r < 0) { + log_err(cd, _("Failed to read volume key from keyring.")); + kc->error = -EINVAL; + return -EINVAL; + } + + *r_vk = crypt_alloc_volume_key(kc->i_volume_key_size, kc->i_volume_key); + if (!*r_vk) { + kc->error = -ENOMEM; + return kc->error; + } + + return 0; +} + +static int get_volume_key_by_vk_in_keyring(struct crypt_device *cd, + struct crypt_keyslot_context *kc, + int keyslot __attribute__((unused)), + struct volume_key **r_vk) +{ + return get_key_by_vk_in_keyring(cd, kc, -2 /* unused */, -2 /* unused */, r_vk); +} + static void unlock_method_init_internal(struct crypt_keyslot_context *kc) { assert(kc); @@ -369,6 +405,8 @@ static void unlock_method_init_internal(struct crypt_keyslot_context *kc) kc->error = 0; kc->i_passphrase = NULL; kc->i_passphrase_size = 0; + kc->i_volume_key = NULL; + kc->i_volume_key_size = 0; } void crypt_keyslot_unlock_by_keyring_internal(struct crypt_keyslot_context *kc, @@ -483,6 +521,27 @@ void crypt_keyslot_unlock_by_token_init_internal(struct crypt_keyslot_context *k unlock_method_init_internal(kc); } +void crypt_keyslot_unlock_by_vk_in_keyring_internal(struct crypt_keyslot_context *kc, + const char *key_description) +{ + assert(kc); + + kc->type = CRYPT_KC_TYPE_VK_KEYRING; + kc->u.vk_kr.key_description = key_description; + + kc->get_luks2_key = get_key_by_vk_in_keyring; + kc->get_luks2_volume_key = get_volume_key_by_vk_in_keyring; + kc->get_luks1_volume_key = NULL; + kc->get_passphrase = NULL; /* keyslot key context does not provide passphrase */ + kc->get_plain_volume_key = NULL; + kc->get_bitlk_volume_key = NULL; + kc->get_fvault2_volume_key = NULL; + kc->get_verity_volume_key = NULL; + kc->get_integrity_volume_key = NULL; + unlock_method_init_internal(kc); +} + + void crypt_keyslot_context_destroy_internal(struct crypt_keyslot_context *kc) { if (!kc) @@ -491,6 +550,9 @@ void crypt_keyslot_context_destroy_internal(struct crypt_keyslot_context *kc) crypt_safe_free(kc->i_passphrase); kc->i_passphrase = NULL; kc->i_passphrase_size = 0; + crypt_safe_free(kc->i_volume_key); + kc->i_volume_key = NULL; + kc->i_volume_key_size = 0; } void crypt_keyslot_context_free(struct crypt_keyslot_context *kc) @@ -606,6 +668,26 @@ int crypt_keyslot_context_init_by_keyring(struct crypt_device *cd, return 0; } +int crypt_keyslot_context_init_by_vk_in_keyring(struct crypt_device *cd, + const char *key_description, + struct crypt_keyslot_context **kc) +{ + struct crypt_keyslot_context *tmp; + + if (!kc) + return -EINVAL; + + tmp = malloc(sizeof(*tmp)); + if (!tmp) + return -ENOMEM; + + crypt_keyslot_unlock_by_vk_in_keyring_internal(tmp, key_description); + + *kc = tmp; + + return 0; +} + int crypt_keyslot_context_get_error(struct crypt_keyslot_context *kc) { return kc ? kc->error : -EINVAL; @@ -645,6 +727,8 @@ const char *keyslot_context_type_string(const struct crypt_keyslot_context *kc) return "key"; case CRYPT_KC_TYPE_KEYRING: return "keyring"; + case CRYPT_KC_TYPE_VK_KEYRING: + return "volume key in keyring"; default: return ""; } diff --git a/lib/keyslot_context.h b/lib/keyslot_context.h index d05183a9..ca49b0d1 100644 --- a/lib/keyslot_context.h +++ b/lib/keyslot_context.h @@ -79,12 +79,17 @@ struct crypt_keyslot_context { struct { const char *key_description; } kr; + struct { + const char *key_description; + } vk_kr; } u; int error; char *i_passphrase; size_t i_passphrase_size; + char *i_volume_key; + size_t i_volume_key_size; keyslot_context_get_key get_luks2_key; keyslot_context_get_volume_key get_luks1_volume_key; @@ -122,6 +127,9 @@ void crypt_keyslot_unlock_by_token_init_internal(struct crypt_keyslot_context *k void crypt_keyslot_unlock_by_keyring_internal(struct crypt_keyslot_context *kc, const char *key_description); +void crypt_keyslot_unlock_by_vk_in_keyring_internal(struct crypt_keyslot_context *kc, + const char *key_description); + const char *keyslot_context_type_string(const struct crypt_keyslot_context *kc); #endif /* KEYSLOT_CONTEXT_H */ diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 54074a5a..b107bcfe 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -1294,6 +1294,22 @@ int crypt_keyslot_context_init_by_keyring(struct crypt_device *cd, const char *key_description, struct crypt_keyslot_context **kc); +/** + * Initialize keyslot context via volume key stored in a keyring. + * + * @param cd crypt device handle initialized to LUKS device context + * + * @param key_description kernel keyring key description library should look + * for passphrase in. The key can be passed either as number in ASCII, + * or a text representation in the form "%:" + * @param kc returns crypt keyslot context handle type CRYPT_KC_TYPE_KEYRING + * + * @return zero on success or negative errno otherwise. + */ +int crypt_keyslot_context_init_by_vk_in_keyring(struct crypt_device *cd, + const char *key_description, + struct crypt_keyslot_context **kc); + /** * Get error code per keyslot context from last failed call. * @@ -1341,6 +1357,10 @@ int crypt_keyslot_context_set_pin(struct crypt_device *cd, * (@link crypt_keyslot_context_init_by_keyring @endlink) */ #define CRYPT_KC_TYPE_KEYRING INT16_C(5) +/** keyslot context initialized by description of a keyring key containing the volume key + * (@link crypt_keyslot_context_init_by_vk_in_keyring @endlink) + */ +#define CRYPT_KC_TYPE_VK_KEYRING INT16_C(6) /** @} */ /** diff --git a/lib/libcryptsetup.sym b/lib/libcryptsetup.sym index 4371a7dc..29357e84 100644 --- a/lib/libcryptsetup.sym +++ b/lib/libcryptsetup.sym @@ -174,6 +174,7 @@ CRYPTSETUP_2.7 { crypt_get_hw_encryption_key_size; crypt_get_vk_keyring_type; crypt_keyslot_context_init_by_keyring; + crypt_keyslot_context_init_by_vk_in_keyring; crypt_resume_by_keyslot_context; crypt_set_keyring_to_link; crypt_set_vk_keyring_type; diff --git a/lib/utils_keyring.c b/lib/utils_keyring.c index d470be3c..031af99a 100644 --- a/lib/utils_keyring.c +++ b/lib/utils_keyring.c @@ -162,6 +162,7 @@ static key_serial_t keyring_process_proc_keys_line(char *line, const char *type, } /* inspired by keyutils written by David Howells (dhowells@redhat.com), returns 0 ID on failure */ + static key_serial_t find_key_by_type_and_desc(const char *type, const char *desc, key_serial_t destringid) { key_serial_t id; @@ -264,6 +265,54 @@ int keyring_get_key(const char *key_desc, return keyring_get_passphrase(key_desc, key, key_size); } +int keyring_read_by_id(const char *key_desc, + char **passphrase, + size_t *passphrase_len) +{ +#ifdef KERNEL_KEYRING + int err; + key_serial_t kid; + long ret; + char *buf = NULL; + size_t len = 0; + + do + kid = request_key(key_type_name(USER_KEY), key_desc, NULL, 0); + while (kid < 0 && errno == EINTR); + + kid = keyring_by_name(key_desc); + if (kid < 0) + return kid; + else if (kid == 0) + return -ENOENT; + + /* just get payload size */ + ret = keyctl_read(kid, NULL, 0); + if (ret > 0) { + len = ret; + buf = crypt_safe_alloc(len); + if (!buf) + return -ENOMEM; + + /* retrieve actual payload data */ + ret = keyctl_read(kid, buf, len); + } + + if (ret < 0) { + err = errno; + crypt_safe_free(buf); + return -err; + } + + *passphrase = buf; + *passphrase_len = len; + + return 0; +#else + return -ENOTSUP; +#endif +} + int keyring_get_passphrase(const char *key_desc, char **passphrase, size_t *passphrase_len) diff --git a/lib/utils_keyring.h b/lib/utils_keyring.h index 9c5db0bc..5556095b 100644 --- a/lib/utils_keyring.h +++ b/lib/utils_keyring.h @@ -37,6 +37,10 @@ int keyring_get_key(const char *key_desc, char **key, size_t *key_size); +int keyring_read_by_id(const char *key_desc, + char **passphrase, + size_t *passphrase_len); + int keyring_get_passphrase(const char *key_desc, char **passphrase, size_t *passphrase_len);