diff --git a/lib/luks2/luks2.h b/lib/luks2/luks2.h index 8cc9ae9c..edec73b4 100644 --- a/lib/luks2/luks2.h +++ b/lib/luks2/luks2.h @@ -227,6 +227,11 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd, /* * Generic LUKS2 digest */ +int LUKS2_digests_by_segment(struct crypt_device *cd, + struct luks2_hdr *hdr, + int segment, + digests_t digests); + int LUKS2_digests_verify_by_segment(struct crypt_device *cd, struct luks2_hdr *hdr, int segment, @@ -338,6 +343,7 @@ int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uin int crypt_use_keyring_for_vk(const struct crypt_device *cd); int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk); void crypt_drop_keyring_key(struct crypt_device *cd, const char *key_description); +const char *crypt_get_key_description_by_keyslot(struct crypt_device *cd, int keyslot); struct luks_phdr; int LUKS2_luks1_to_luks2(struct crypt_device *cd, diff --git a/lib/luks2/luks2_digest.c b/lib/luks2/luks2_digest.c index 4172060e..f0b508c5 100644 --- a/lib/luks2/luks2_digest.c +++ b/lib/luks2/luks2_digest.c @@ -182,10 +182,43 @@ int LUKS2_digests_verify_by_segment(struct crypt_device *cd, const struct volume_key *vk, digests_t digests) { - char segment_name[16]; const digest_handler *h; + digests_t tmp; + int *digest, r, i = 0; + + digest = digests ? digests : tmp; + + r = LUKS2_digests_by_segment(cd, hdr, segment, digest); + if (r) + return r; + + while (i < LUKS2_DIGEST_MAX && digest[i] != -1) { + log_dbg("Verifying key digest %d.", digest[i]); + + h = LUKS2_digest_handler(cd, digest[i]); + if (!h) + return -EINVAL; + + r = h->verify(cd, digest[i], vk->key, vk->keylength); + if (r < 0) { + log_dbg("Digest %d (%s) verify failed with %d.", digest[i], h->name, r); + return r; + } + + i++; + } + + return 0; +} + +int LUKS2_digests_by_segment(struct crypt_device *cd, + struct luks2_hdr *hdr, + int segment, + digests_t digests) +{ + char segment_name[16]; json_object *jobj_digests, *jobj_digest_segments; - int digest, r, i = 0; + int i = 0; json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests); @@ -197,25 +230,10 @@ int LUKS2_digests_verify_by_segment(struct crypt_device *cd, if (!LUKS2_array_jobj(jobj_digest_segments, segment_name)) continue; - digest = atoi(key); - log_dbg("Verifying key digest %d.", digest); - - h = LUKS2_digest_handler(cd, digest); - if (!h) - return -EINVAL; - - r = h->verify(cd, digest, vk->key, vk->keylength); - if (r < 0) { - log_dbg("Digest %d (%s) verify failed with %d.", digest, h->name, r); - return r; - } - - if (digests) - digests[i] = digest; - i++; + digests[i++] = atoi(key); } - if (digests && i < LUKS2_DIGEST_MAX) + if (i < LUKS2_DIGEST_MAX) digests[i] = -1; return i ? 0 : -ENOENT; diff --git a/lib/luks2/luks2_token.c b/lib/luks2/luks2_token.c index c8e7c88f..c54b6b40 100644 --- a/lib/luks2/luks2_token.c +++ b/lib/luks2/luks2_token.c @@ -398,8 +398,10 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd, keyslot = r; - if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) + if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) { + crypt_volume_key_set_description(vk, crypt_get_key_description_by_keyslot(cd, keyslot)); r = crypt_volume_key_load_in_keyring(cd, vk); + } if (r >= 0 && name) r = LUKS2_activate(cd, name, vk, flags); @@ -442,8 +444,10 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd, keyslot = r; - if (r >= 0 && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) + if (r >= 0 && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) { + crypt_volume_key_set_description(vk, crypt_get_key_description_by_keyslot(cd, keyslot)); r = crypt_volume_key_load_in_keyring(cd, vk); + } if (r >= 0 && name) r = LUKS2_activate(cd, name, vk, flags); diff --git a/lib/setup.c b/lib/setup.c index 8b6f98ff..b8ba64ae 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -2017,35 +2017,61 @@ int crypt_repair(struct crypt_device *cd, return r; } -static int crypt_get_segment_key_description(struct crypt_device *cd, char **segment_key_desc, int segment) +static const char *crypt_get_key_description_by_digests(struct crypt_device *cd, digests_t digests) { - char *key_desc; - int r; - size_t len; + char *desc, digests_str[17]; + int i = 0, r; + size_t len, off = 0; - if (!crypt_get_uuid(cd) || segment > 9 || segment < 0) - return -EINVAL; + if (!crypt_get_uuid(cd)) + return NULL; - len = strlen(crypt_get_uuid(cd)) + 14; - - key_desc = malloc(len); - if (!key_desc) - return -ENOMEM; - - r = snprintf(key_desc, len, "%s:%s-%u", "cryptsetup", crypt_get_uuid(cd), segment); - if (r < 0 || (size_t)r >= len) { - free(key_desc); - return -EINVAL; + while (i < LUKS2_DIGEST_MAX && digests[i] != -1) { + r = snprintf(digests_str + off, sizeof(digests_str) - off, "d%u", digests[i++]); + if (r < 0 || (size_t)r >= sizeof(digests_str) - off) + return NULL; + off += (size_t) r; } - *segment_key_desc = key_desc; + /* "cryptsetup:-" + \0 */ + len = strlen(crypt_get_uuid(cd)) + strlen(digests_str) + 13; - return 0; + desc = malloc(len); + if (!desc) + return NULL; + + r = snprintf(desc, len, "%s:%s-%s", "cryptsetup", crypt_get_uuid(cd), digests_str); + if (r < 0 || (size_t)r >= len) { + free(desc); + return NULL; + } + + return desc; +} + +static const char *crypt_get_key_description_by_segment(struct crypt_device *cd, int segment) +{ + digests_t digests; + + if (LUKS2_digests_by_segment(cd, &cd->u.luks2.hdr, segment, digests)) + return NULL; + + return crypt_get_key_description_by_digests(cd, digests); +} + +/* curently internal only (candidate for new API call) */ +const char *crypt_get_key_description_by_keyslot(struct crypt_device *cd, int keyslot) +{ + digests_t digests; + + if (LUKS2_digests_by_keyslot(cd, &cd->u.luks2.hdr, keyslot, digests)) + return NULL; + + return crypt_get_key_description_by_digests(cd, digests); } int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size) { - char *key_desc; struct crypt_dm_active_device dmd = {}; int r; @@ -2083,11 +2109,11 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size) } if (crypt_key_in_keyring(cd)) { - r = crypt_get_segment_key_description(cd, &key_desc, CRYPT_DEFAULT_SEGMENT); + crypt_volume_key_set_description(dmd.u.crypt.vk, crypt_get_key_description_by_segment(cd, CRYPT_DEFAULT_SEGMENT)); + r = crypt_volume_key_get_description(dmd.u.crypt.vk) ? 0 : -EINVAL; if (r) goto out; - crypt_volume_key_set_description(dmd.u.crypt.vk, key_desc); dmd.flags |= CRYPT_ACTIVATE_KEYRING_KEY; } @@ -2111,7 +2137,6 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size) goto out; } - if (new_size == dmd.size) { log_dbg("Device has already requested size %" PRIu64 " sectors.", dmd.size); @@ -2429,6 +2454,7 @@ int crypt_resume_by_passphrase(struct crypt_device *cd, keyslot = r; if (crypt_use_keyring_for_vk(cd)) { + crypt_volume_key_set_description(vk, crypt_get_key_description_by_keyslot(cd, keyslot)); r = crypt_volume_key_load_in_keyring(cd, vk); if (r < 0) goto out; @@ -2492,14 +2518,15 @@ int crypt_resume_by_keyfile_offset(struct crypt_device *cd, r = LUKS2_keyslot_open(cd, keyslot, CRYPT_DEFAULT_SEGMENT, passphrase_read, passphrase_size_read, &vk); if (r < 0) goto out; + keyslot = r; if (crypt_use_keyring_for_vk(cd)) { + crypt_volume_key_set_description(vk, crypt_get_key_description_by_keyslot(cd, keyslot)); r = crypt_volume_key_load_in_keyring(cd, vk); if (r < 0) goto out; } - keyslot = r; r = dm_resume_and_reinstate_key(cd, name, vk); if (r) log_err(cd, _("Error during resuming device %s.\n"), name); @@ -2880,24 +2907,24 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot) /* internal only */ int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk) { - char *seg_key_desc = NULL; + const char *key_desc; int r; - if (!vk) + if (!vk || !cd) return -EINVAL; - r = crypt_get_segment_key_description(cd, &seg_key_desc, CRYPT_DEFAULT_SEGMENT); - if (!r) - r = keyring_add_key_in_thread_keyring(seg_key_desc, vk->key, vk->keylength); - - if (r) { - free(seg_key_desc); - log_err(cd, _("Failed to load key in kernel keyring.\n")); - } else { - crypt_volume_key_set_description(vk, seg_key_desc); - crypt_set_key_in_keyring(cd, 1); + key_desc = crypt_volume_key_get_description(vk); + if (!key_desc) { + log_dbg("Invalid key description"); + return -EINVAL; } + r = keyring_add_key_in_thread_keyring(key_desc, vk->key, vk->keylength); + if (r) + log_err(cd, _("Failed to load key in kernel keyring.\n")); + else + crypt_set_key_in_keyring(cd, 1); + return r; } @@ -2943,6 +2970,7 @@ static int _activate_by_passphrase(struct crypt_device *cd, keyslot = r; if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) { + crypt_volume_key_set_description(vk, crypt_get_key_description_by_keyslot(cd, keyslot)); r = crypt_volume_key_load_in_keyring(cd, vk); if (r < 0) goto out; @@ -3080,6 +3108,7 @@ int crypt_activate_by_keyfile_offset(struct crypt_device *cd, keyslot = r; if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) { + crypt_volume_key_set_description(vk, crypt_get_key_description_by_keyslot(cd, keyslot)); r = crypt_volume_key_load_in_keyring(cd, vk); if (r < 0) goto out; @@ -3204,6 +3233,7 @@ int crypt_activate_by_volume_key(struct crypt_device *cd, log_err(cd, _("Volume key does not match the volume.\n")); if (!r && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) { + crypt_volume_key_set_description(vk, crypt_get_key_description_by_segment(cd, CRYPT_DEFAULT_SEGMENT)); r = crypt_volume_key_load_in_keyring(cd, vk); if (!r) flags |= CRYPT_ACTIVATE_KEYRING_KEY; diff --git a/tests/api-test-2.c b/tests/api-test-2.c index e7ac6855..363e8219 100644 --- a/tests/api-test-2.c +++ b/tests/api-test-2.c @@ -384,7 +384,7 @@ static key_serial_t _kernel_key_by_segment(struct crypt_device *cd, int segment) { char key_description[1024]; - if (snprintf(key_description, sizeof(key_description), "cryptsetup:%s-%u", crypt_get_uuid(cd), segment) < 1) + if (snprintf(key_description, sizeof(key_description), "cryptsetup:%s-d%u", crypt_get_uuid(cd), segment) < 1) return -1; return request_key("logon", key_description, NULL, 0);