Add keyslot_context for volume key stored in a keyring.

This commit is contained in:
Daniel Zatovic
2023-08-15 17:23:35 +02:00
parent 1f2dac34d0
commit 6bcd9ed52c
6 changed files with 166 additions and 0 deletions

View File

@@ -362,6 +362,42 @@ static int get_luks1_volume_key_by_keyring(struct crypt_device *cd,
return r; 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) static void unlock_method_init_internal(struct crypt_keyslot_context *kc)
{ {
assert(kc); assert(kc);
@@ -369,6 +405,8 @@ static void unlock_method_init_internal(struct crypt_keyslot_context *kc)
kc->error = 0; kc->error = 0;
kc->i_passphrase = NULL; kc->i_passphrase = NULL;
kc->i_passphrase_size = 0; 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, 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); 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) void crypt_keyslot_context_destroy_internal(struct crypt_keyslot_context *kc)
{ {
if (!kc) if (!kc)
@@ -491,6 +550,9 @@ void crypt_keyslot_context_destroy_internal(struct crypt_keyslot_context *kc)
crypt_safe_free(kc->i_passphrase); crypt_safe_free(kc->i_passphrase);
kc->i_passphrase = NULL; kc->i_passphrase = NULL;
kc->i_passphrase_size = 0; 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) 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; 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) int crypt_keyslot_context_get_error(struct crypt_keyslot_context *kc)
{ {
return kc ? kc->error : -EINVAL; return kc ? kc->error : -EINVAL;
@@ -645,6 +727,8 @@ const char *keyslot_context_type_string(const struct crypt_keyslot_context *kc)
return "key"; return "key";
case CRYPT_KC_TYPE_KEYRING: case CRYPT_KC_TYPE_KEYRING:
return "keyring"; return "keyring";
case CRYPT_KC_TYPE_VK_KEYRING:
return "volume key in keyring";
default: default:
return "<unknown>"; return "<unknown>";
} }

View File

@@ -79,12 +79,17 @@ struct crypt_keyslot_context {
struct { struct {
const char *key_description; const char *key_description;
} kr; } kr;
struct {
const char *key_description;
} vk_kr;
} u; } u;
int error; int error;
char *i_passphrase; char *i_passphrase;
size_t i_passphrase_size; 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_key get_luks2_key;
keyslot_context_get_volume_key get_luks1_volume_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, void crypt_keyslot_unlock_by_keyring_internal(struct crypt_keyslot_context *kc,
const char *key_description); 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); const char *keyslot_context_type_string(const struct crypt_keyslot_context *kc);
#endif /* KEYSLOT_CONTEXT_H */ #endif /* KEYSLOT_CONTEXT_H */

View File

@@ -1294,6 +1294,22 @@ int crypt_keyslot_context_init_by_keyring(struct crypt_device *cd,
const char *key_description, const char *key_description,
struct crypt_keyslot_context **kc); 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 "%<key_type>:<key_name>"
* @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. * 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) * (@link crypt_keyslot_context_init_by_keyring @endlink)
*/ */
#define CRYPT_KC_TYPE_KEYRING INT16_C(5) #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)
/** @} */ /** @} */
/** /**

View File

@@ -174,6 +174,7 @@ CRYPTSETUP_2.7 {
crypt_get_hw_encryption_key_size; crypt_get_hw_encryption_key_size;
crypt_get_vk_keyring_type; crypt_get_vk_keyring_type;
crypt_keyslot_context_init_by_keyring; crypt_keyslot_context_init_by_keyring;
crypt_keyslot_context_init_by_vk_in_keyring;
crypt_resume_by_keyslot_context; crypt_resume_by_keyslot_context;
crypt_set_keyring_to_link; crypt_set_keyring_to_link;
crypt_set_vk_keyring_type; crypt_set_vk_keyring_type;

View File

@@ -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 */ /* 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) static key_serial_t find_key_by_type_and_desc(const char *type, const char *desc, key_serial_t destringid)
{ {
key_serial_t id; 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); 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, int keyring_get_passphrase(const char *key_desc,
char **passphrase, char **passphrase,
size_t *passphrase_len) size_t *passphrase_len)

View File

@@ -37,6 +37,10 @@ int keyring_get_key(const char *key_desc,
char **key, char **key,
size_t *key_size); 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, int keyring_get_passphrase(const char *key_desc,
char **passphrase, char **passphrase,
size_t *passphrase_len); size_t *passphrase_len);